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