30 struct TX11GLManager::TGLContext_t {
32 TGLContext_t() : fWindowIndex(-1), fPixmapIndex(-1), fX11Pixmap(0), fW(0),
33 fH(0), fX(0), fY(0), fGLXContext(0), fDirect(kFALSE),
34 fXImage(0), fNextFreeContext(0), fDirectGC(0), fPixmapGC(0)
48 GLXContext fGLXContext;
52 std::vector<UChar_t> fBUBuffer;
54 TGLContext_t *fNextFreeContext;
61 typedef std::deque<TX11GLManager::TGLContext_t> DeviceTable_t;
62 typedef DeviceTable_t::size_type SizeType_t;
63 typedef std::map<Int_t, XVisualInfo *> WinTable_t;
64 XSetWindowAttributes dummyAttr;
73 TX11PixGuard(Display *dpy, Pixmap pix) : fDpy(dpy), fPix(pix) {}
74 ~TX11PixGuard(){
if (fPix) XFreePixmap(fDpy, fPix);}
75 void Stop(){fPix = 0;}
78 TX11PixGuard(
const TX11PixGuard &);
79 TX11PixGuard &operator = (
const TX11PixGuard &);
89 TGLXCtxGuard(Display *dpy, GLXContext ctx) : fDpy(dpy), fCtx(ctx) {}
90 ~TGLXCtxGuard(){
if (fCtx) glXDestroyContext(fDpy, fCtx);}
91 void Stop(){fCtx = 0;}
94 TGLXCtxGuard(
const TGLXCtxGuard &);
95 TGLXCtxGuard &operator = (
const TGLXCtxGuard &);
103 TXImageGuard(
const TXImageGuard &);
104 TXImageGuard &operator = (
const TXImageGuard &);
107 explicit TXImageGuard(XImage *im) : fImage(im) {}
108 ~TXImageGuard(){
if (fImage) XDestroyImage(fImage);}
109 void Stop(){fImage = 0;}
115 const Int_t dblBuff[] =
128 const Int_t *snglBuff = dblBuff + 1;
130 class TX11GLManager::TX11GLImpl {
135 WinTable_t fGLWindows;
136 DeviceTable_t fGLContexts;
138 TGLContext_t *fNextFreeContext;
141 TX11GLImpl(
const TX11GLImpl &);
142 TX11GLImpl &operator = (
const TX11GLImpl &);
145 ClassImp(TX11GLManager);
150 TX11GLManager::TX11GLImpl::TX11GLImpl() : fDpy(0), fNextFreeContext(0)
152 fDpy =
reinterpret_cast<Display *
>(gVirtualX->GetDisplay());
161 TX11GLManager::TX11GLImpl::~TX11GLImpl()
163 for (SizeType_t i = 0, e = fGLContexts.size(); i < e; ++i) {
164 TGLContext_t &ctx = fGLContexts[i];
166 if (ctx.fGLXContext) {
167 ::Warning(
"TX11GLManager::~TX11GLManager",
"opengl device with index %ld was not destroyed", (Long_t)i);
168 glXDestroyContext(fDpy, ctx.fGLXContext);
170 if (ctx.fPixmapIndex != -1) {
171 gVirtualX->SelectWindow(ctx.fPixmapIndex);
172 gVirtualX->ClosePixmap();
174 XDestroyImage(ctx.fXImage);
184 TX11GLManager::TX11GLManager() : fPimpl(new TX11GLImpl)
187 gROOT->GetListOfSpecials()->Add(
this);
194 TX11GLManager::~TX11GLManager()
203 Int_t TX11GLManager::InitGLWindow(Window_t winID)
205 XVisualInfo *visInfo = glXChooseVisual(
206 fPimpl->fDpy, DefaultScreen(fPimpl->fDpy),
207 const_cast<Int_t *>(dblBuff)
211 Error(
"InitGLWindow",
"No good visual found!\n");
216 UInt_t w = 0, h = 0, b = 0, d = 0;
218 XGetGeometry(fPimpl->fDpy, winID, &root, &x, &y, &w, &h, &b, &d);
220 XSetWindowAttributes attr(dummyAttr);
221 attr.colormap = XCreateColormap(fPimpl->fDpy, root, visInfo->visual, AllocNone);
222 attr.event_mask = NoEventMask;
223 attr.backing_store = Always;
224 attr.bit_gravity = NorthWestGravity;
226 ULong_t mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWBackingStore | CWBitGravity;
229 Window glWin = XCreateWindow(
232 0, visInfo->depth, InputOutput,
233 visInfo->visual, mask, &attr
237 XMapWindow(fPimpl->fDpy, glWin);
240 Int_t x11Ind = gVirtualX->AddWindow(glWin, w, h);
243 fPimpl->fGLWindows[x11Ind] = visInfo;
253 Int_t TX11GLManager::CreateGLContext(Int_t winInd)
255 GLXContext glxCtx = glXCreateContext(fPimpl->fDpy, fPimpl->fGLWindows[winInd], None, True);
258 Error(
"CreateContext",
"glXCreateContext failed\n");
263 if (TGLContext_t *ctx = fPimpl->fNextFreeContext) {
264 Int_t ind = ctx->fWindowIndex;
265 ctx->fWindowIndex = winInd;
266 ctx->fGLXContext = glxCtx;
267 fPimpl->fNextFreeContext = fPimpl->fNextFreeContext->fNextFreeContext;
270 TGLXCtxGuard glxCtxGuard(fPimpl->fDpy, glxCtx);
272 newDev.fWindowIndex = winInd;
273 newDev.fGLXContext = glxCtx;
275 fPimpl->fGLContexts.push_back(newDev);
278 return Int_t(fPimpl->fGLContexts.size()) - 1;
286 Bool_t TX11GLManager::MakeCurrent(Int_t ctxInd)
288 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
289 return glXMakeCurrent(fPimpl->fDpy, gVirtualX->GetWindowID(ctx.fWindowIndex), ctx.fGLXContext);
296 void TX11GLManager::Flush(Int_t ctxInd)
298 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
299 Window winID = gVirtualX->GetWindowID(ctx.fWindowIndex);
301 if (ctx.fPixmapIndex == -1)
302 glXSwapBuffers(fPimpl->fDpy, winID);
303 else if (ctx.fXImage && ctx.fDirect) {
305 ctx.fDirectGC = XCreateGC(fPimpl->fDpy, winID, 0, 0);
307 if (!ctx.fDirectGC) {
308 Error(
"Flush",
"XCreateGC failed while copying pixmap\n");
309 ctx.fDirect = kFALSE;
313 XCopyArea(fPimpl->fDpy, ctx.fX11Pixmap, winID, ctx.fDirectGC, 0, 0, ctx.fW, ctx.fH, ctx.fX, ctx.fY);
321 Bool_t TX11GLManager::CreateGLPixmap(TGLContext_t &ctx)
324 Pixmap x11Pix = XCreatePixmap(fPimpl->fDpy, gVirtualX->GetWindowID(ctx.fWindowIndex), ctx.fW,
325 ctx.fH, fPimpl->fGLWindows[ctx.fWindowIndex]->depth);
328 Error(
"CreateGLPixmap",
"XCreatePixmap failed\n");
332 TX11PixGuard pixGuard(fPimpl->fDpy, x11Pix);
335 XVisualInfo *visInfo = fPimpl->fGLWindows[ctx.fWindowIndex];
336 XImage *testIm = XCreateImage(fPimpl->fDpy, visInfo->visual, visInfo->depth, ZPixmap, 0, 0, ctx.fW, ctx.fH, 32, 0);
339 TXImageGuard imGuard(testIm);
340 testIm->data =
static_cast<Char_t *
>(malloc(testIm->bytes_per_line * testIm->height));
343 Error(
"CreateGLPixmap",
"Cannot malloc XImage data\n");
347 if (XInitImage(testIm)) {
348 ctx.fPixmapIndex = gVirtualX->AddPixmap(x11Pix, ctx.fW, ctx.fH);
349 ctx.fBUBuffer.resize(testIm->bytes_per_line * testIm->height);
350 ctx.fX11Pixmap = x11Pix;
351 ctx.fXImage = testIm;
356 Error(
"CreateGLPixmap",
"XInitImage error!\n");
358 Error(
"CreateGLPixmap",
"XCreateImage error!\n");
367 Bool_t TX11GLManager::AttachOffScreenDevice(Int_t ctxInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
370 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
372 newCtx.fWindowIndex = ctx.fWindowIndex;
373 newCtx.fW = w, newCtx.fH = h, newCtx.fX = x, newCtx.fY = y;
374 newCtx.fGLXContext = ctx.fGLXContext;
376 if (CreateGLPixmap(newCtx)) {
377 ctx.fPixmapIndex = newCtx.fPixmapIndex;
378 ctx.fX11Pixmap = newCtx.fX11Pixmap;
379 ctx.fW = w, ctx.fH = h, ctx.fX = x, ctx.fY = y;
380 ctx.fDirect = kFALSE;
381 ctx.fXImage = newCtx.fXImage;
382 ctx.fBUBuffer.swap(newCtx.fBUBuffer);
393 Bool_t TX11GLManager::ResizeOffScreenDevice(Int_t ctxInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
396 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
398 if (ctx.fPixmapIndex != -1) {
399 if (TMath::Abs(Int_t(w) - Int_t(ctx.fW)) > 1 || TMath::Abs(Int_t(h) - Int_t(ctx.fH)) > 1) {
401 newCtx.fWindowIndex = ctx.fWindowIndex;
402 newCtx.fW = w, newCtx.fH = h, newCtx.fX = x, newCtx.fY = y;
403 newCtx.fGLXContext = ctx.fGLXContext;
405 if (CreateGLPixmap(newCtx)) {
406 gVirtualX->SelectWindow(ctx.fPixmapIndex);
407 gVirtualX->ClosePixmap();
408 ctx.fPixmapIndex = newCtx.fPixmapIndex;
409 ctx.fX11Pixmap = newCtx.fX11Pixmap;
410 ctx.fW = w, ctx.fH = h, ctx.fX = x, ctx.fY = y;
411 ctx.fDirect = kFALSE;
412 if (ctx.fXImage) XDestroyImage(ctx.fXImage);
413 ctx.fXImage = newCtx.fXImage;
414 ctx.fBUBuffer.swap(newCtx.fBUBuffer);
417 Error(
"ResizeOffScreenDevice",
"Resize failed\n");
431 void TX11GLManager::SelectOffScreenDevice(Int_t ctxInd)
433 gVirtualX->SelectWindow(fPimpl->fGLContexts[ctxInd].fPixmapIndex);
440 void TX11GLManager::MarkForDirectCopy(Int_t ctxInd, Bool_t dir)
442 if (fPimpl->fGLContexts[ctxInd].fPixmapIndex != -1)
443 fPimpl->fGLContexts[ctxInd].fDirect = dir;
451 void TX11GLManager::ReadGLBuffer(Int_t ctxInd)
453 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
455 if (ctx.fPixmapIndex != -1 && ctx.fXImage) {
457 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
458 glReadBuffer(GL_BACK);
459 glReadPixels(0, 0, ctx.fW, ctx.fH, GL_BGRA, GL_UNSIGNED_BYTE, &ctx.fBUBuffer[0]);
462 ctx.fPixmapGC = XCreateGC(fPimpl->fDpy, ctx.fX11Pixmap, 0, 0);
466 char *dest = ctx.fXImage->data;
467 const UChar_t *src = &ctx.fBUBuffer[ctx.fW * 4 * (ctx.fH - 1)];
468 for (UInt_t i = 0, e = ctx.fH; i < e; ++i) {
469 memcpy(dest, src, ctx.fW * 4);
473 XPutImage(fPimpl->fDpy, ctx.fX11Pixmap, ctx.fPixmapGC, ctx.fXImage, 0, 0, 0, 0, ctx.fW, ctx.fH);
475 Error(
"ReadGLBuffer",
"XCreateGC error while attempt to copy XImage\n");
483 void TX11GLManager::DeleteGLContext(Int_t ctxInd)
485 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
488 glXDestroyContext(fPimpl->fDpy, ctx.fGLXContext);
492 if (ctx.fPixmapIndex != -1) {
493 gVirtualX->SelectWindow(ctx.fPixmapIndex);
494 gVirtualX->ClosePixmap();
495 ctx.fPixmapIndex = -1;
497 XDestroyImage(ctx.fXImage);
501 XFreeGC(fPimpl->fDpy, ctx.fDirectGC), ctx.fDirectGC = 0;
503 XFreeGC(fPimpl->fDpy, ctx.fPixmapGC), ctx.fPixmapGC = 0;
506 ctx.fNextFreeContext = fPimpl->fNextFreeContext;
507 fPimpl->fNextFreeContext = &ctx;
508 ctx.fWindowIndex = ctxInd;
515 Int_t TX11GLManager::GetVirtualXInd(Int_t ctxInd)
517 return fPimpl->fGLContexts[ctxInd].fPixmapIndex;
524 void TX11GLManager::ExtractViewport(Int_t ctxInd, Int_t *viewport)
526 TGLContext_t &ctx = fPimpl->fGLContexts[ctxInd];
528 if (ctx.fPixmapIndex != -1) {
531 viewport[2] = ctx.fW;
532 viewport[3] = ctx.fH;
540 void TX11GLManager::PaintSingleObject(TVirtualGLPainter *p)
549 void TX11GLManager::PrintViewer(TVirtualViewer3D *vv)
557 Bool_t TX11GLManager::SelectManip(TVirtualGLManip *manip,
const TGLCamera * camera,
const TGLRect * rect,
const TGLBoundingBox * sceneBox)
559 return manip->Select(*camera, *rect, *sceneBox);
566 void TX11GLManager::PanObject(TVirtualGLPainter *o, Int_t x, Int_t y)
574 Bool_t TX11GLManager::PlotSelected(TVirtualGLPainter *plot, Int_t px, Int_t py)
576 return plot->PlotSelected(px, py);
582 char *TX11GLManager::GetPlotInfo(TVirtualGLPainter *plot, Int_t px, Int_t py)
584 return plot->GetPlotInfo(px, py);