00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00028
00029
00030
00031
00032
00033 struct TX11GLManager::TGLContext_t {
00034
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 }
00040 Int_t fWindowIndex;
00041 Int_t fPixmapIndex;
00042
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
00054 XImage *fXImage;
00055 std::vector<UChar_t> fBUBuffer;
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
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
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
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
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
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
00155
00156 fDpy = reinterpret_cast<Display *>(gVirtualX->GetDisplay());
00157 }
00158
00159
00160
00161 TX11GLManager::TX11GLImpl::~TX11GLImpl()
00162 {
00163
00164
00165
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
00189
00190 gGLManager = this;
00191 gROOT->GetListOfSpecials()->Add(this);
00192 }
00193
00194
00195
00196 TX11GLManager::~TX11GLManager()
00197 {
00198
00199
00200 delete fPimpl;
00201 }
00202
00203
00204
00205 Int_t TX11GLManager::InitGLWindow(Window_t winID)
00206 {
00207
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
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
00241 XMapWindow(fPimpl->fDpy, glWin);
00242
00243
00244 Int_t x11Ind = gVirtualX->AddWindow(glWin, w, h);
00245
00246
00247 fPimpl->fGLWindows[x11Ind] = visInfo;
00248
00249 return x11Ind;
00250 }
00251
00252
00253
00254 Int_t TX11GLManager::CreateGLContext(Int_t winInd)
00255 {
00256
00257
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
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
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
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
00324
00325
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
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
00370
00371
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
00396
00397
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
00434
00435 gVirtualX->SelectWindow(fPimpl->fGLContexts[ctxInd].fPixmapIndex);
00436 }
00437
00438
00439
00440 void TX11GLManager::MarkForDirectCopy(Int_t ctxInd, Bool_t dir)
00441 {
00442
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
00453
00454
00455 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00456
00457 if (ctx.fPixmapIndex != -1 && ctx.fXImage) {
00458
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
00467
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
00486
00487 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
00488
00489
00490 glXDestroyContext(fPimpl->fDpy, ctx.fGLXContext);
00491 ctx.fGLXContext = 0;
00492
00493
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
00518
00519 return fPimpl->fGLContexts[ctxInd].fPixmapIndex;
00520 }
00521
00522
00523
00524 void TX11GLManager::ExtractViewport(Int_t ctxInd, Int_t *viewport)
00525 {
00526
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
00543
00544 p->Paint();
00545 }
00546
00547
00548
00549 void TX11GLManager::PrintViewer(TVirtualViewer3D *vv)
00550 {
00551
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
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
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
00577 return plot->PlotSelected(px, py);
00578 }
00579
00580
00581 char *TX11GLManager::GetPlotInfo(TVirtualGLPainter *plot, Int_t px, Int_t py)
00582 {
00583
00584 return plot->GetPlotInfo(px, py);
00585 }