Logo ROOT  
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
36This class encapsulates window-system specific information about a
37GL-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%zx)->SetContext((TGLWidget *)0x%zx, (TGLContext *)0x%zx)",
63 (size_t)this, (size_t)wid, (size_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
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
102namespace {
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
123void 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%zx)->MakeCurrent()", (size_t)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%zx)->SwapBuffers()", (size_t)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
228{
229 if (!gVirtualX->IsCmdThread()) {
230 gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->Release()", (size_t)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
249void 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
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
329void 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
459Identifier of a shared GL-context.
460Objects shared among GL-contexts include:
461display-list definitions, texture objects and shader programs.
462*/
463
465
467
468////////////////////////////////////////////////////////////////////////////////
469/// Constructor.
470
472fFontManager(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)
583 delete this;
584 }
585}
unsigned int GLenum
Definition: GL_glu.h:266
#define e(i)
Definition: RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition: RtypesCore.h:45
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:364
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:220
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
Int_t gDebug
Definition: TROOT.cxx:592
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:61
#define gROOT
Definition: TROOT.h:404
char * Form(const char *fmt,...)
#define R__LOCKGUARD(mutex)
#define gVirtualX
Definition: TVirtualX.h:338
void Stop() const
Definition: TGLUtil.h:1283
Identifier of a shared GL-context.
Definition: TGLContext.h:81
virtual ~TGLContextIdentity()
Destructor.
Definition: TGLContext.cxx:479
static TGLContextIdentity * GetDefaultIdentity()
Get identity of a default Gl context. Static.
Definition: TGLContext.cxx:547
void CheckDestroy()
Private function called when reference count is reduced.
Definition: TGLContext.cxx:577
TGLContextIdentity()
Constructor.
Definition: TGLContext.cxx:471
std::pair< UInt_t, Int_t > DLRange_t
Definition: TGLContext.h:117
TGLFontManager * fFontManager
Definition: TGLContext.h:84
static TGLContextIdentity * fgDefaultIdentity
Definition: TGLContext.h:126
void DeleteGLResources()
Delete GL resources registered for destruction.
Definition: TGLContext.cxx:522
void Release(TGLContext *ctx)
Remove context ctx from the list of references.
Definition: TGLContext.cxx:496
DLTrash_t::const_iterator DLTrashIt_t
Definition: TGLContext.h:119
static TGLContextIdentity * GetCurrent()
Find identitfy of current context. Static.
Definition: TGLContext.cxx:538
TGLFontManager * GetFontManager()
Get the free-type font-manager associated with this context-identity.
Definition: TGLContext.cxx:568
void AddRef(TGLContext *ctx)
Add context ctx to the list of references.
Definition: TGLContext.cxx:487
void RegisterDLNameRangeToWipe(UInt_t base, Int_t size)
Remember dl range for deletion in next MakeCurrent or dtor execution.
Definition: TGLContext.cxx:514
static TGLContext * GetDefaultContextAny()
Get the first GL context with the default identity.
Definition: TGLContext.cxx:558
DLTrash_t fDLTrash
Definition: TGLContext.h:123
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 TGLContext * GetCurrentContext()
Ask wgl what HGLRC is current and look up corresponding TGLContext.
This class encapsulates window-system specific information about a GL-context and alows their proper ...
Definition: TGLContext.h:31
Bool_t fValid
Definition: TGLContext.h:41
void Release()
Make the context invalid and (do thread switch, if needed) free resources.
Definition: TGLContext.cxx:412
void SwapBuffers()
If context is valid (TGLPaintDevice, for which context was created still exists), swap buffers (in ca...
Definition: TGLContext.cxx:395
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
static Bool_t fgGlewInitDone
Definition: TGLContext.h:45
std::unique_ptr< TGLContextPrivate > fPimpl
Definition: TGLContext.h:38
virtual ~TGLContext()
TGLContext dtor.
Definition: TGLContext.cxx:428
Bool_t MakeCurrent()
If context is valid (TGLPaintDevice, for which context was created still exists), make it current.
Definition: TGLContext.cxx:362
void SetContext(TGLWidget *widget, const TGLContext *shareList)
X11 gl-context creation.
Definition: TGLContext.cxx:329
static void GlewInit()
Initialize GLEW - static private function.
Definition: TGLContext.cxx:85
TGLContext(TGLWidget *glWidget, Bool_t shareDefault=kTRUE, const TGLContext *shareList=0)
TGLContext ctor "from" TGLWidget.
Definition: TGLContext.cxx:51
Bool_t ClearCurrent()
Reset current context.
Definition: TGLContext.cxx:386
TGLContextIdentity * fIdentity
Definition: TGLContext.h:43
TGLPaintDevice * fDevice
Definition: TGLContext.h:37
static TGLContext * GetCurrent()
Ask TGLContextPrivate to lookup context in its internal map.
Definition: TGLContext.cxx:451
Bool_t fFromCtor
Definition: TGLContext.h:40
A FreeType GL font manager.
void ClearFontTrash()
Delete FTFFont objects registered for destruction.
virtual void AddContext(TGLContext *ctx)=0
virtual void RemoveContext(TGLContext *ctx)=0
GL window with context.
Definition: TGLWidget.h:28
std::pair< void *, void * > GetInnerData() const
Dpy*, XVisualInfo *.
Definition: TGLWidget.cxx:241
Handle_t GetId() const
Definition: TGObject.h:37
TOneArgGuard< Func, Arg > make_guard(Func f, Arg a)
Definition: TGLUtil.h:1326
const char * True