ROOT  6.06/09
Reference Guide
TGLContext.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov, Jun 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <stdexcept>
13 #include <algorithm>
14 #include <memory>
15 
16 #include "TVirtualX.h"
17 #include "GuiTypes.h"
18 #include "TString.h"
19 #include "TError.h"
20 
21 #include "TROOT.h"
22 #include "TVirtualMutex.h"
23 
24 #include "TGLContextPrivate.h"
25 #include "RConfigure.h"
26 #include "TGLIncludes.h"
27 #include "TGLContext.h"
28 #include "TGLWidget.h"
29 #include "TGLFormat.h"
30 #include "TGLUtil.h"
31 
32 #include "TGLFontManager.h"
33 
34 /** \class TGLContext
35 \ingroup opengl
36 This class encapsulates window-system specific information about a
37 GL-context and alows their proper management in ROOT.
38 */
39 
41 
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 /// TGLContext ctor "from" TGLWidget.
46 /// Is shareDefault is true, the shareList is set from default
47 /// context-identity. Otherwise the given shareList is used (can be
48 /// null).
49 /// Makes thread switching.
50 
52  const TGLContext *shareList)
53  : fDevice(wid),
54  fPimpl(0),
55  fFromCtor(kTRUE),
56  fValid(kFALSE),
57  fIdentity(0)
58 {
59  if (shareDefault)
61 
62  if (!gVirtualX->IsCmdThread()) {
63  gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SetContext((TGLWidget *)0x%lx, (TGLContext *)0x%lx)",
64  (ULong_t)this, (ULong_t)wid, (ULong_t)shareList));
65  } else {
66 
68 
69  SetContext(wid, shareList);
70  }
71 
72  if (shareDefault)
74  else
75  fIdentity = shareList ? shareList->GetIdentity() : new TGLContextIdentity;
76 
77  fIdentity->AddRef(this);
78 
79  fFromCtor = kFALSE;
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Initialize GLEW - static private function.
84 /// Called immediately after creation of the first GL context.
85 
87 {
88  if (!fgGlewInitDone)
89  {
90  GLenum status = glewInit();
91  if (status != GLEW_OK)
92  Warning("TGLContext::GlewInit", "GLEW initalization failed.");
93  else if (gDebug > 0)
94  Info("TGLContext::GlewInit", "GLEW initalization successful.");
96  }
97 }
98 
99 //==============================================================================
100 #ifdef WIN32
101 //==============================================================================
102 
103 namespace {
104 
105  struct LayoutCompatible_t {
106  void *fDummy0;
107  void *fDummy1;
108  HWND *fPHwnd;
109  unsigned char fDummy2;
110  unsigned fDummy3;
111  unsigned short fDummy4;
112  unsigned short fDummy5;
113  void *fDummy6;
114  unsigned fDummy7:2;
115  };
116 
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 ///WIN32 gl-context creation. Defined as a member-function (this code removed from ctor)
121 ///to make WIN32/X11 separation cleaner.
122 ///This function is public only for calls via gROOT and called from ctor.
123 
124 void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
125 {
126  if (!fFromCtor) {
127  Error("TGLContext::SetContext", "SetContext must be called only from ctor");
128  return;
129  }
130 
131  std::auto_ptr<TGLContextPrivate> safe_ptr(fPimpl = new TGLContextPrivate);
132  LayoutCompatible_t *trick =
133  reinterpret_cast<LayoutCompatible_t *>(widget->GetId());
134  HWND hWND = *trick->fPHwnd;
135  HDC hDC = GetWindowDC(hWND);
136 
137  if (!hDC) {
138  Error("TGLContext::SetContext", "GetWindowDC failed");
139  throw std::runtime_error("GetWindowDC failed");
140  }
141 
142  const Rgl::TGuardBase &dcGuard = Rgl::make_guard(ReleaseDC, hWND, hDC);
143  if (HGLRC glContext = wglCreateContext(hDC)) {
144  if (shareList && !wglShareLists(shareList->fPimpl->fGLContext, glContext)) {
145  wglDeleteContext(glContext);
146  Error("TGLContext::SetContext", "Context sharing failed!");
147  throw std::runtime_error("Context sharing failed");
148  }
149  fPimpl->fHWND = hWND;
150  fPimpl->fHDC = hDC;
151  fPimpl->fGLContext = glContext;
152  } else {
153  Error("TGLContext::SetContext", "wglCreateContext failed");
154  throw std::runtime_error("wglCreateContext failed");
155  }
156 
157  //Register context for "parent" gl-device.
158  fValid = kTRUE;
159  fDevice->AddContext(this);
161 
162  dcGuard.Stop();
163  safe_ptr.release();
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 ///If context is valid (TGLPaintDevice, for which context was created still exists),
168 ///make it current.
169 
171 {
172  if (!fValid) {
173  Error("TGLContext::MakeCurrent", "This context is invalid.");
174  return kFALSE;
175  }
176 
177  if (!gVirtualX->IsCmdThread())
178  return Bool_t(gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->MakeCurrent()", this)));
179  else {
180 
182 
183  Bool_t rez = wglMakeCurrent(fPimpl->fHDC, fPimpl->fGLContext);
184  if (rez) {
185  if (!fgGlewInitDone)
186  GlewInit();
188  }
189  return rez;
190  }
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 ///Reset current context.
195 
197 {
198  return wglMakeCurrent(0, 0);
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 ///If context is valid (TGLPaintDevice, for which context was created still exists),
203 ///swap buffers (in case of P-buffer call glFinish()).
204 
206 {
207  if (!fValid) {
208  Error("TGLContext::SwapBuffers", "This context is invalid.");
209  return;
210  }
211 
212  if (!gVirtualX->IsCmdThread())
213  gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SwapBuffers()", this));
214  else {
215 
217 
218  if (fPimpl->fHWND)
219  wglSwapLayerBuffers(fPimpl->fHDC, WGL_SWAP_MAIN_PLANE);
220  else
221  glFinish();
222  }
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 ///Make the context invalid and (do thread switch, if needed)
227 ///free resources.
228 
229 void TGLContext::Release()
230 {
231  if (!gVirtualX->IsCmdThread()) {
232  gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->Release()", this));
233  return;
234  }
235 
237 
238  if (fPimpl->fHWND)
239  ReleaseDC(fPimpl->fHWND, fPimpl->fHDC);
240 
242  wglDeleteContext(fPimpl->fGLContext);
243  fValid = kFALSE;
244 }
245 
246 #elif defined(R__HAS_COCOA)
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 ///This function is public only for calls via gROOT and called from ctor.
250 
251 void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
252 {
253  if (!fFromCtor) {
254  Error("TGLContext::SetContext", "SetContext must be called only from ctor");
255  return;
256  }
257 
258  std::auto_ptr<TGLContextPrivate> safe_ptr(fPimpl = new TGLContextPrivate);
259 
260  fPimpl->fGLContext = gVirtualX->CreateOpenGLContext(widget->GetId(), shareList ? shareList->fPimpl->fGLContext : 0);
261  fPimpl->fWindowID = widget->GetId();
262 
263  fValid = kTRUE;
264  fDevice->AddContext(this);
266 
267  safe_ptr.release();
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 ///If context is valid (TGLPaintDevice, for which context was created still exists),
272 ///make it current.
273 
275 {
276  if (!fValid) {
277  Error("TGLContext::MakeCurrent", "This context is invalid.");
278  return kFALSE;
279  }
280 
281  const Bool_t rez = gVirtualX->MakeOpenGLContextCurrent(fPimpl->fGLContext, fPimpl->fWindowID);
282  if (rez) {
283  if (!fgGlewInitDone)
284  GlewInit();
286 
287  }
288 
289  return rez;
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 ///Reset current context.
294 
296 {
297  return kFALSE;
298 }
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 ///If context is valid (TGLPaintDevice, for which context was created still exists),
302 ///swap buffers (in case of P-buffer call glFinish()).
303 
305 {
306  if (!fValid) {
307  Error("TGLContext::SwapBuffers", "This context is invalid.");
308  return;
309  }
310 
311  gVirtualX->FlushOpenGLBuffer(fPimpl->fGLContext);
312 }
313 
314 ////////////////////////////////////////////////////////////////////////////////
315 ///Make the context invalid and free resources.
316 
317 void TGLContext::Release()
318 {
320  gVirtualX->DeleteOpenGLContext(fPimpl->fGLContext);
321  fValid = kFALSE;
322 }
323 
324 //==============================================================================
325 #else // X11
326 //==============================================================================
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 ///X11 gl-context creation. Defined as a member-function (this code removed from ctor)
330 ///to make WIN32/X11 separation cleaner.
331 ///This function is public only for calls via gROOT and called from ctor.
332 
333 void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
334 {
335  if (!fFromCtor) {
336  Error("TGLContext::SetContext", "SetContext must be called only from ctor");
337  return;
338  }
339 
340  std::auto_ptr<TGLContextPrivate> safe_ptr(fPimpl = new TGLContextPrivate);
341  Display *dpy = static_cast<Display *>(widget->GetInnerData().first);
342  XVisualInfo *visInfo = static_cast<XVisualInfo *>(widget->GetInnerData().second);
343 
344  GLXContext glCtx = shareList ? glXCreateContext(dpy, visInfo, shareList->fPimpl->fGLContext, True)
345  : glXCreateContext(dpy, visInfo, None, True);
346 
347  if (!glCtx) {
348  Error("TGLContext::SetContext", "glXCreateContext failed!");
349  throw std::runtime_error("glXCreateContext failed!");
350  }
351 
352  fPimpl->fDpy = dpy;
353  fPimpl->fVisualInfo = visInfo;
354  fPimpl->fGLContext = glCtx;
355  fPimpl->fWindowID = widget->GetId();
356 
357  fValid = kTRUE;
358  fDevice->AddContext(this);
360 
361  safe_ptr.release();
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 ///If context is valid (TGLPaintDevice, for which context was created still exists),
366 ///make it current.
367 
369 {
370  if (!fValid) {
371  Error("TGLContext::MakeCurrent", "This context is invalid.");
372  return kFALSE;
373  }
374 
375  if (fPimpl->fWindowID != 0) {
376  const Bool_t rez = glXMakeCurrent(fPimpl->fDpy, fPimpl->fWindowID,
377  fPimpl->fGLContext);
378  if (rez) {
379  if (!fgGlewInitDone)
380  GlewInit();
382  }
383  return rez;
384  }
385 
386  return kFALSE;
387 }
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 ///Reset current context.
391 
393 {
394  return glXMakeCurrent(fPimpl->fDpy, None, 0);
395 }
396 
397 ////////////////////////////////////////////////////////////////////////////////
398 ///If context is valid (TGLPaintDevice, for which context was created still exists),
399 ///swap buffers (in case of P-buffer call glFinish()).
400 
402 {
403  if (!fValid) {
404  Error("TGLContext::SwapCurrent", "This context is invalid.");
405  return;
406  }
407 
408  if (fPimpl->fWindowID != 0)
409  glXSwapBuffers(fPimpl->fDpy, fPimpl->fWindowID);
410  else
411  glFinish();
412 }
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 ///Make the context invalid and (do thread switch, if needed)
416 ///free resources.
417 
419 {
421  glXDestroyContext(fPimpl->fDpy, fPimpl->fGLContext);
422  fValid = kFALSE;
423 }
424 
425 //==============================================================================
426 #endif
427 //==============================================================================
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 ///TGLContext dtor. If it's called before TGLPaintDevice's dtor
431 ///(context is valid) resource will be freed and context
432 ///un-registered.
433 
435 {
436  if (fValid) {
437  Release();
438  fDevice->RemoveContext(this);
439  }
440 
441  fIdentity->Release(this);
442 
443  delete fPimpl;
444 }
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 ///We can have several shared contexts,
448 ///and gl-scene wants to know, if some context
449 ///(defined by its identity) can be used.
450 
452 {
453  return fIdentity;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 ///Ask TGLContextPrivate to lookup context in its internal map.
458 
460 {
462 }
463 
464 
465 /** \class TGLContextIdentity
466 \ingroup opengl
467 Identifier of a shared GL-context.
468 Objects shared among GL-contexts include:
469 display-list definitions, texture objects and shader programs.
470 */
471 
473 
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 /// Constructor.
478 
479 TGLContextIdentity::TGLContextIdentity():
480 fFontManager(0), fCnt(0), fClientCnt(0)
481 {
482 }
483 
484 ////////////////////////////////////////////////////////////////////////////////
485 /// Destructor.
486 
488 {
489  if (fFontManager) delete fFontManager;
490 }
491 
492 ////////////////////////////////////////////////////////////////////////////////
493 ///Add context ctx to the list of references.
494 
496 {
497  ++fCnt;
498  fCtxs.push_back(ctx);
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 ///Remove context ctx from the list of references.
503 
505 {
506  CtxList_t::iterator i = std::find(fCtxs.begin(), fCtxs.end(), ctx);
507  if (i != fCtxs.end())
508  {
509  fCtxs.erase(i);
510  --fCnt;
511  CheckDestroy();
512  }
513  else
514  {
515  Error("TGLContextIdentity::Release", "unregistered context.");
516  }
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 ///Remember dl range for deletion in next MakeCurrent or dtor execution.
521 
523 {
524  fDLTrash.push_back(DLRange_t(base, size));
525 }
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 ///Delete GL resources registered for destruction.
529 
531 {
532  if (!fDLTrash.empty())
533  {
534  for (DLTrashIt_t it = fDLTrash.begin(), e = fDLTrash.end(); it != e; ++it)
535  glDeleteLists(it->first, it->second);
536  fDLTrash.clear();
537  }
538 
539  if (fFontManager)
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 ///Find identitfy of current context. Static.
545 
547 {
549  return ctx ? ctx->GetIdentity() : 0;
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 ///Get identity of a default Gl context. Static.
554 
556 {
557  if (fgDefaultIdentity == 0)
559  return fgDefaultIdentity;
560 }
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 ///Get the first GL context with the default identity.
564 ///Can return zero, but that's OK, too. Static.
565 
567 {
568  if (fgDefaultIdentity == 0 || fgDefaultIdentity->fCtxs.empty())
569  return 0;
570  return fgDefaultIdentity->fCtxs.front();
571 }
572 
573 ////////////////////////////////////////////////////////////////////////////////
574 ///Get the free-type font-manager associated with this context-identity.
575 
577 {
579  return fFontManager;
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
583 ///Private function called when reference count is reduced.
584 
586 {
587  if (fCnt <= 0 && fClientCnt <= 0)
588  {
589  if (this == fgDefaultIdentity)
590  fgDefaultIdentity = 0;
591  delete this;
592  }
593 }
static TGLContext * GetDefaultContextAny()
Get the first GL context with the default identity.
Definition: TGLContext.cxx:566
static void RegisterContext(TGLContext *ctx)
Register gl-context to find it later as current (GetCurrentContext)
static void RemoveContext(TGLContext *ctx)
Un-register deleted context.
static TGLContextIdentity * GetDefaultIdentity()
Get identity of a default Gl context. Static.
Definition: TGLContext.cxx:555
std::pair< UInt_t, Int_t > DLRange_t
Definition: TGLContext.h:120
Identifier of a shared GL-context.
Definition: TGLContext.h:83
Bool_t fValid
Definition: TGLContext.h:44
#define gROOT
Definition: TROOT.h:340
void Stop() const
Definition: TGLUtil.h:1285
int Int_t
Definition: RtypesCore.h:41
TAlienJobStatus * status
Definition: TAlienJob.cxx:51
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:63
const Bool_t kFALSE
Definition: Rtypes.h:92
DLTrash_t::const_iterator DLTrashIt_t
Definition: TGLContext.h:122
virtual void RemoveContext(TGLContext *ctx)=0
TGLContextIdentity * fIdentity
Definition: TGLContext.h:46
std::pair< void *, void * > GetInnerData() const
Dpy*, XVisualInfo *.
Definition: TGLWidget.cxx:241
void CheckDestroy()
Private function called when reference count is reduced.
Definition: TGLContext.cxx:585
void Release(TGLContext *ctx)
Remove context ctx from the list of references.
Definition: TGLContext.cxx:504
const char * True
XVisualInfo * fVisualInfo
virtual void AddContext(TGLContext *ctx)=0
TGLPaintDevice * fDevice
Definition: TGLContext.h:40
UChar_t mod R__LOCKGUARD2(gSrvAuthenticateMutex)
DLTrash_t fDLTrash
Definition: TGLContext.h:126
TGLContextIdentity * GetIdentity() const
We can have several shared contexts, and gl-scene wants to know, if some context (defined by its iden...
Definition: TGLContext.cxx:451
Bool_t MakeCurrent()
If context is valid (TGLPaintDevice, for which context was created still exists), make it current...
Definition: TGLContext.cxx:368
void Info(const char *location, const char *msgfmt,...)
TGLContextPrivate * fPimpl
Definition: TGLContext.h:41
void Error(const char *location, const char *msgfmt,...)
virtual ~TGLContextIdentity()
Destructor.
Definition: TGLContext.cxx:487
static TGLContextIdentity * GetCurrent()
Find identitfy of current context. Static.
Definition: TGLContext.cxx:546
ClassImp(TGLContext)
#define None
Definition: TGWin32.h:68
TGLContext(TGLWidget *glWidget, Bool_t shareDefault=kTRUE, const TGLContext *shareList=0)
TGLContext ctor "from" TGLWidget.
Definition: TGLContext.cxx:51
TGLFontManager * fFontManager
Definition: TGLContext.h:87
TOneArgGuard< Func, Arg > make_guard(Func f, Arg a)
Definition: TGLUtil.h:1328
static TGLContextIdentity * fgDefaultIdentity
Definition: TGLContext.h:129
unsigned int UInt_t
Definition: RtypesCore.h:42
char * Form(const char *fmt,...)
void DeleteGLResources()
Delete GL resources registered for destruction.
Definition: TGLContext.cxx:530
GL window with context.
Definition: TGLWidget.h:35
static TGLContext * GetCurrentContext()
Ask wgl what HGLRC is current and look up corresponding TGLContext.
void Warning(const char *location, const char *msgfmt,...)
static void GlewInit()
Initialize GLEW - static private function.
Definition: TGLContext.cxx:86
TGLFontManager * GetFontManager()
Get the free-type font-manager associated with this context-identity.
Definition: TGLContext.cxx:576
#define gVirtualX
Definition: TVirtualX.h:362
void SetContext(TGLWidget *widget, const TGLContext *shareList)
X11 gl-context creation.
Definition: TGLContext.cxx:333
void SwapBuffers()
If context is valid (TGLPaintDevice, for which context was created still exists), swap buffers (in ca...
Definition: TGLContext.cxx:401
This class encapsulates window-system specific information about a GL-context and alows their proper ...
Definition: TGLContext.h:33
unsigned long ULong_t
Definition: RtypesCore.h:51
Bool_t ClearCurrent()
Reset current context.
Definition: TGLContext.cxx:392
void AddRef(TGLContext *ctx)
Add context ctx to the list of references.
Definition: TGLContext.cxx:495
void Release()
Make the context invalid and (do thread switch, if needed) free resources.
Definition: TGLContext.cxx:418
static TGLContext * GetCurrent()
Ask TGLContextPrivate to lookup context in its internal map.
Definition: TGLContext.cxx:459
A FreeType GL font manager.
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
static Bool_t fgGlewInitDone
Definition: TGLContext.h:48
const Bool_t kTRUE
Definition: Rtypes.h:91
void ClearFontTrash()
Delete FTFFont objects registered for destruction.
void RegisterDLNameRangeToWipe(UInt_t base, Int_t size)
Remember dl range for deletion in next MakeCurrent or dtor execution.
Definition: TGLContext.cxx:522
Bool_t fFromCtor
Definition: TGLContext.h:43
Handle_t GetId() const
Definition: TGObject.h:52
virtual ~TGLContext()
TGLContext dtor.
Definition: TGLContext.cxx:434