// @(#)root/gx11:$Name: $:$Id: TX11GL.cxx,v 1.8 2005/08/23 11:29:06 brun Exp $
// Author: Timur Pocheptsov 09/08/2004
/*************************************************************************
* Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TX11GL //
// //
// The TX11GL is X11 implementation of TVirtualGLImp class. //
// //
//////////////////////////////////////////////////////////////////////////
#include <deque>
#include <map>
#include "TVirtualViewer3D.h"
#include "TVirtualX.h"
#include "TX11GL.h"
#include "TError.h"
#include "TROOT.h"
ClassImp(TX11GL)
//______________________________________________________________________________
TX11GL::TX11GL() : fDpy(0), fVisInfo(0)
{
}
//______________________________________________________________________________
Window_t TX11GL::CreateGLWindow(Window_t wind)
{
if(!fDpy)
fDpy = (Display *)gVirtualX->GetDisplay();
static int dblBuf[] = {
GLX_DOUBLEBUFFER,
#ifdef STEREO_GL
GLX_STEREO,
#endif
GLX_RGBA, GLX_DEPTH_SIZE, 16,
GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,None
};
static int * snglBuf = dblBuf + 1;
if(!fVisInfo){
fVisInfo = glXChooseVisual(fDpy, DefaultScreen(fDpy), dblBuf);
if(!fVisInfo)
fVisInfo = glXChooseVisual(fDpy, DefaultScreen(fDpy), snglBuf);
if(!fVisInfo){
::Error("TX11GL::CreateGLWindow", "no good visual found");
return 0;
}
}
Int_t xval = 0, yval = 0;
UInt_t wval = 0, hval = 0, border = 0, d = 0;
Window root;
XGetGeometry(fDpy, wind, &root, &xval, &yval, &wval, &hval, &border, &d);
ULong_t mask = 0;
XSetWindowAttributes attr;
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap(fDpy, root, fVisInfo->visual, AllocNone);
attr.event_mask = NoEventMask;
attr.backing_store = Always;
attr.bit_gravity = NorthWestGravity;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask |
CWBackingStore | CWBitGravity;
Window GLWin = XCreateWindow(fDpy, wind, xval, yval, wval, hval,
0, fVisInfo->depth, InputOutput,
fVisInfo->visual, mask, &attr);
XMapWindow(fDpy, GLWin);
return (Window_t)GLWin;
}
//______________________________________________________________________________
ULong_t TX11GL::CreateContext(Window_t)
{
return (ULong_t)glXCreateContext(fDpy, fVisInfo, None, GL_TRUE);
}
//______________________________________________________________________________
void TX11GL::DeleteContext(ULong_t ctx)
{
glXDestroyContext(fDpy, (GLXContext)ctx);
}
//______________________________________________________________________________
void TX11GL::MakeCurrent(Window_t wind, ULong_t ctx)
{
glXMakeCurrent(fDpy, (GLXDrawable)wind, (GLXContext)ctx);
}
//______________________________________________________________________________
void TX11GL::SwapBuffers(Window_t wind)
{
glXSwapBuffers(fDpy, (GLXDrawable)wind);
}
////////////////////////////////////////GL Manager stuff///////////////////////////////////////
namespace {
struct PaintDevice {
//these are numbers returned by gVirtualX->AddWindow and gVirtualX->AddPixmap
//need both, I can have a pixmap, which is always created for certain window
Int_t fWindowIndex;
Int_t fPixmapIndex;
//Pixmap info, not used for double buffered windows
Pixmap fX11Pixmap; //required by TX11GLManager::DirectCopy and explicit destruction in resize
GLXPixmap fGLXPixmap;
//Pixmap parameters
UInt_t fRealW;//to check, if we really need new pixmap during resize
UInt_t fRealH;
UInt_t fCurrW;//used by DirectCopy
UInt_t fCurrH;
//Where to XCopyArea pixmap
Int_t fX;//used by DirectCopy
Int_t fY;
//ctx, used for off-screen and double-buffered gl painting
GLXContext fGLXContext;
Bool_t fDirect;
//
PaintDevice *fNextFreeDevice;
};
typedef std::deque<PaintDevice> DeviceTable_t;
typedef DeviceTable_t::size_type size_type;
typedef std::map<Int_t, XVisualInfo *> WinTable_t;
XSetWindowAttributes dummyAttr;
PaintDevice dummyDevice;
const Int_t dblBuff[] = {
GLX_DOUBLEBUFFER,
GLX_RGBA,
GLX_DEPTH_SIZE, 16,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None
};
const Int_t *snglBuff = dblBuff + 1;
//Here I can have one universal guard class, but :
//I'm not shure about X11/GLX function linkage (are they always extern "C" ???)
//man does not show return types of these functions, in old K&R C it's int
//in such cases, but in C++ there are no implicit int. So
class X11PixGuard {
private:
Display *fDpy;
Pixmap fPix;
public:
X11PixGuard(Display *dpy, Pixmap pix) : fDpy(dpy), fPix(pix) {}
~X11PixGuard(){if (fPix) XFreePixmap(fDpy, fPix);}
void Stop(){fPix = 0;}
private:
X11PixGuard(const X11PixGuard &);
X11PixGuard &operator = (const X11PixGuard &);
};
class GLXPixGuard {
private:
Display *fDpy;
GLXPixmap fPix;
public:
GLXPixGuard(Display *dpy, GLXPixmap pix) : fDpy(dpy), fPix(pix) {}
~GLXPixGuard(){if (fPix) glXDestroyGLXPixmap(fDpy, fPix);}
void Stop(){fPix = 0;}
private:
GLXPixGuard(const GLXPixGuard &);
GLXPixGuard &operator = (const GLXPixGuard &);
};
class GLXCtxGuard {
private:
Display *fDpy;
GLXContext fCtx;
public:
GLXCtxGuard(Display *dpy, GLXContext ctx) : fDpy(dpy), fCtx(ctx) {}
~GLXCtxGuard(){if (fCtx) glXDestroyContext(fDpy, fCtx);}
void Stop(){fCtx = 0;}
private:
GLXCtxGuard(const GLXCtxGuard &);
GLXCtxGuard &operator = (const GLXCtxGuard &);
};
Int_t length(PaintDevice *p)
{
Int_t rez = 0;
while(p && ++rez, p = p->fNextFreeDevice);
return rez;
}
}
class TX11GLManager::TX11GLImpl {
public:
TX11GLImpl();
~TX11GLImpl();
WinTable_t fGLWindows;
DeviceTable_t fPaintDevices;
Display *fDpy;
PaintDevice *fNextFreeDevice;
private:
TX11GLImpl(const TX11GLImpl &);
TX11GLImpl &operator = (const TX11GLImpl &);
};
ClassImp(TX11GLManager)
//______________________________________________________________________________
TX11GLManager::TX11GLImpl::TX11GLImpl() : fDpy(0), fNextFreeDevice(0)
{
fDpy = reinterpret_cast<Display *>(gVirtualX->GetDisplay());
}
//______________________________________________________________________________
TX11GLManager::TX11GLImpl::~TX11GLImpl()
{
//destroys only gl contexts and GLXPixmap,
//pixmaps and windows must be
//closed through gVirtualX
for (size_type i = 0, e = fPaintDevices.size(); i < e; ++i) {
PaintDevice &currDev = fPaintDevices[i];
if (GLXContext ctx = currDev.fGLXContext) {
::Warning("TX11GLManager::~TX11GLManager", "opengl device with index %d was not destroyed", i);
glXDestroyContext(fDpy, ctx);
if (currDev.fPixmapIndex != -1) {
gVirtualX->SelectWindow(currDev.fPixmapIndex);
gVirtualX->ClosePixmap();
glXDestroyGLXPixmap(fDpy, currDev.fGLXPixmap);
}
}
}
}
//______________________________________________________________________________
TX11GLManager::TX11GLManager() : fPimpl(new TX11GLImpl)
{
gGLManager = this;
gROOT->GetListOfSpecials()->Add(this);
}
//______________________________________________________________________________
TX11GLManager::~TX11GLManager()
{
delete fPimpl;
}
//______________________________________________________________________________
Int_t TX11GLManager::InitGLWindow(Window_t winID, Bool_t isOffScreen)
{
//Try to find correct visual
XVisualInfo *visInfo = glXChooseVisual(
fPimpl->fDpy, DefaultScreen(fPimpl->fDpy),
const_cast<Int_t *>(isOffScreen ? snglBuff : dblBuff)
);
if (!visInfo) {
Error("InitWindow", "No good visual found!\n");
return -1;
}
Int_t xVal = 0, yVal = 0;
UInt_t wVal = 0, hVal = 0, border = 0, d = 0;
Window root = 0;
XGetGeometry(fPimpl->fDpy, winID, &root, &xVal, &yVal, &wVal, &hVal, &border, &d);
XSetWindowAttributes attr(dummyAttr);
attr.colormap = XCreateColormap(fPimpl->fDpy, root, visInfo->visual, AllocNone);
attr.event_mask = NoEventMask;
attr.backing_store = Always;
attr.bit_gravity = NorthWestGravity;
ULong_t mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWBackingStore | CWBitGravity;
//Create window with specific visual
Window glWin = XCreateWindow(
fPimpl->fDpy, winID,
xVal, yVal, wVal, hVal,
0, visInfo->depth, InputOutput,
visInfo->visual, mask, &attr
);
XMapWindow(fPimpl->fDpy, glWin);
//register window for gVirtualX
Int_t x11Ind = gVirtualX->AddWindow(glWin, wVal, hVal);
//register this window for gl manager
fPimpl->fGLWindows[x11Ind] = visInfo;
return x11Ind;
}
//______________________________________________________________________________
Int_t TX11GLManager::CreateGLContext(Int_t winInd)
{
//context creation requires Display * and XVisualInfo (was saved for such winInd)
GLXContext glxCtx = glXCreateContext(fPimpl->fDpy, fPimpl->fGLWindows[winInd], None, True);
if (!glxCtx) {
Error("CreateContext", "glXCreateContext failed\n");
return -1;
}
//register new context now
if (PaintDevice *dev = fPimpl->fNextFreeDevice) {
Int_t ind = dev->fWindowIndex;
dev->fWindowIndex = winInd;
dev->fGLXContext = glxCtx;
fPimpl->fNextFreeDevice = fPimpl->fNextFreeDevice->fNextFreeDevice;
return ind;
} else {
GLXCtxGuard glxCtxGuard(fPimpl->fDpy, glxCtx);
PaintDevice newDev(dummyDevice);
newDev.fWindowIndex = winInd;
newDev.fPixmapIndex = -1;//on-screen rendering device
newDev.fGLXContext = glxCtx;
fPimpl->fPaintDevices.push_back(newDev);
glxCtxGuard.Stop();
return Int_t(fPimpl->fPaintDevices.size()) - 1;
}
}
//______________________________________________________________________________
Bool_t TX11GLManager::MakeCurrent(Int_t devInd)
{
//Make gl context current
PaintDevice &currDev = fPimpl->fPaintDevices[devInd];
if (currDev.fPixmapIndex != -1) {
//off-screen rendering into pixmap
return glXMakeCurrent(fPimpl->fDpy, currDev.fGLXPixmap, currDev.fGLXContext);
} else {
Window winID = gVirtualX->GetWindowID(currDev.fWindowIndex);
return glXMakeCurrent(fPimpl->fDpy, winID, currDev.fGLXContext);
}
}
//______________________________________________________________________________
void TX11GLManager::Flush(Int_t devInd, Int_t, Int_t)
{
//swaps buffers for window or copy pixmap
PaintDevice &currDev = fPimpl->fPaintDevices[devInd];
Window winID = gVirtualX->GetWindowID(currDev.fWindowIndex);
if (currDev.fPixmapIndex != -1) {
if (!currDev.fDirect) return;
GC gc = XCreateGC(fPimpl->fDpy, winID, 0, 0);
if (!gc) {
Error("Flush", "XCreateGC failed\n");
currDev.fDirect = kFALSE;
return;
}
XCopyArea(fPimpl->fDpy, currDev.fX11Pixmap, winID, gc, 0, 0, currDev.fCurrW,
currDev.fCurrH, currDev.fX, currDev.fY);
XFreeGC(fPimpl->fDpy, gc);
} else {
glXSwapBuffers(fPimpl->fDpy, winID);
}
}
//______________________________________________________________________________
Bool_t TX11GLManager::CreateGLPixmap(Int_t winInd, Int_t x, Int_t y, UInt_t w, UInt_t h, Int_t prevInd)
{
//creates new x11 pixmap, gl pixmap, gl context
Pixmap x11Pix = XCreatePixmap(fPimpl->fDpy, gVirtualX->GetWindowID(winInd), w,
h, fPimpl->fGLWindows[winInd]->depth);
if (!x11Pix) {
Error("CreateGLPixmap", "XCreatePixmap failed\n");
return kFALSE;
}
X11PixGuard x11PixGuard(fPimpl->fDpy, x11Pix);
GLXPixmap glxPix = glXCreateGLXPixmap(fPimpl->fDpy, fPimpl->fGLWindows[winInd], x11Pix);
if (!glxPix) {
Error("CreateGLPixmap", "glXCreateGLXPixmap failed\n");
return kFALSE;
}
GLXPixGuard glxPixGuard(fPimpl->fDpy, glxPix);
if (prevInd == -1 || !fPimpl->fPaintDevices[prevInd].fGLXContext) {
GLXContext glxCtx = glXCreateContext(fPimpl->fDpy, fPimpl->fGLWindows[winInd],
None, True);
if (!glxCtx) {
Error("CreateGLPixmap", "glXCreateContext failed\n");
return kFALSE;
}
GLXCtxGuard glxCtxGuard(fPimpl->fDpy, glxCtx);
PaintDevice newDev = {winInd, gVirtualX->AddPixmap(x11Pix, w, h), x11Pix,
glxPix, w, h, w, h, x, y, glxCtx, kFALSE, 0};
if (prevInd == -1) {
fPimpl->fPaintDevices.push_back(newDev);
} else {
newDev.fNextFreeDevice = fPimpl->fPaintDevices[prevInd].fNextFreeDevice;
fPimpl->fPaintDevices[prevInd] = newDev;
}
glxCtxGuard.Stop();
} else {
PaintDevice &dev = fPimpl->fPaintDevices[prevInd];
XFreePixmap(fPimpl->fDpy, dev.fX11Pixmap);
gVirtualX->AddPixmap(x11Pix, w, h, dev.fPixmapIndex);
dev.fX11Pixmap = x11Pix;
dev.fGLXPixmap = glxPix;
dev.fCurrW = w, dev.fRealW = w;
dev.fCurrH = h, dev.fRealH = h;
dev.fX = x, dev.fY = y;
}
glxPixGuard.Stop();
x11PixGuard.Stop();
return kTRUE;
}
//______________________________________________________________________________
Int_t TX11GLManager::OpenGLPixmap(Int_t winInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
{
//create new X11 pixmap and GLX pixmap and gl context for
//off-screen drawing - new device
if (PaintDevice *dev = fPimpl->fNextFreeDevice) {
//reuse existing place in fPaintDevices
Int_t prevInd = dev->fWindowIndex; //obscure usage of fWindowIndex
if (CreateGLPixmap(winInd, x, y, w, h, prevInd)) {
fPimpl->fNextFreeDevice = fPimpl->fNextFreeDevice->fNextFreeDevice;
return prevInd;
}
} else if (CreateGLPixmap(winInd, x, y, w, h)) {
return Int_t(fPimpl->fPaintDevices.size()) - 1;
}
return -1;
}
//______________________________________________________________________________
void TX11GLManager::ResizeGLPixmap(Int_t pixInd, Int_t x, Int_t y, UInt_t w, UInt_t h)
{
PaintDevice &dev = fPimpl->fPaintDevices[pixInd];
if (w > dev.fRealW || h > dev.fRealH) {
//destroy old pixmap with such index and create
//new in place
CreateGLPixmap(dev.fWindowIndex, x, y, w, h, pixInd);
} else {
//simply change size-description
dev.fX = x;
dev.fY = y;
dev.fCurrW = w;
dev.fCurrH = h;
gVirtualX->AddPixmap(0, w, h, dev.fPixmapIndex);
}
}
//______________________________________________________________________________
void TX11GLManager::SelectGLPixmap(Int_t pixInd)
{
//selects off-screen device to make it
//accessible by gVirtualX
gVirtualX->SelectWindow(fPimpl->fPaintDevices[pixInd].fPixmapIndex);
}
//______________________________________________________________________________
void TX11GLManager::MarkForDirectCopy(Int_t pixInd, Bool_t dir)
{
if (fPimpl->fPaintDevices[pixInd].fPixmapIndex != -1)
fPimpl->fPaintDevices[pixInd].fDirect = dir;
//Part of
//selection-rotation support for TPad/TCanvas
}
//______________________________________________________________________________
void TX11GLManager::DeletePaintDevice(Int_t devInd)
{
PaintDevice &currDev = fPimpl->fPaintDevices[devInd];
//free gl context
glXDestroyContext(fPimpl->fDpy, currDev.fGLXContext);
currDev.fGLXContext = 0;
//if pixmap - destroy
if (currDev.fPixmapIndex != -1) {
gVirtualX->SelectWindow(currDev.fPixmapIndex);
gVirtualX->ClosePixmap();
glXDestroyGLXPixmap(fPimpl->fDpy, currDev.fGLXPixmap);
}
currDev.fNextFreeDevice = fPimpl->fNextFreeDevice;
fPimpl->fNextFreeDevice = &currDev;
currDev.fWindowIndex = devInd;
}
Int_t TX11GLManager::GetVirtualXInd(Int_t glPix)
{
return fPimpl->fPaintDevices[glPix].fPixmapIndex;
}
void TX11GLManager::ExtractViewport(Int_t pixId, Int_t *viewport)
{
PaintDevice &dev = fPimpl->fPaintDevices[pixId];
if (dev.fPixmapIndex != -1) {
viewport[0] = 0;
viewport[1] = dev.fRealH - dev.fCurrH;//dev.fY;
viewport[2] = dev.fCurrW;
viewport[3] = dev.fCurrH;
}
}
//______________________________________________________________________________
void TX11GLManager::DrawViewer(TVirtualViewer3D *vv)
{
vv->DrawViewer();
}
//______________________________________________________________________________
TObject *TX11GLManager::Select(TVirtualViewer3D *vv, Int_t x, Int_t y)
{
return vv->SelectObject(x, y);
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.