Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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%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
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%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
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
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}
#define e(i)
Definition RSha256.hxx:103
const Bool_t kFALSE
Definition RtypesCore.h:92
unsigned long ULong_t
Definition RtypesCore.h:55
bool Bool_t
Definition RtypesCore.h:63
const Bool_t kTRUE
Definition RtypesCore.h:91
#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:590
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:406
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.
static TGLContextIdentity * GetDefaultIdentity()
Get identity of a default Gl context. Static.
void CheckDestroy()
Private function called when reference count is reduced.
TGLContextIdentity()
Constructor.
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.
void Release(TGLContext *ctx)
Remove context ctx from the list of references.
DLTrash_t::const_iterator DLTrashIt_t
Definition TGLContext.h:119
static TGLContextIdentity * GetCurrent()
Find identitfy of current context. Static.
TGLFontManager * GetFontManager()
Get the free-type font-manager associated with this context-identity.
void AddRef(TGLContext *ctx)
Add context ctx to the list of references.
void RegisterDLNameRangeToWipe(UInt_t base, Int_t size)
Remember dl range for deletion in next MakeCurrent or dtor execution.
static TGLContext * GetDefaultContextAny()
Get the first GL context with the default identity.
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.
void SwapBuffers()
If context is valid (TGLPaintDevice, for which context was created still exists), swap buffers (in ca...
TGLContextIdentity * GetIdentity() const
We can have several shared contexts, and gl-scene wants to know, if some context (defined by its iden...
static Bool_t fgGlewInitDone
Definition TGLContext.h:45
std::unique_ptr< TGLContextPrivate > fPimpl
Definition TGLContext.h:38
virtual ~TGLContext()
TGLContext dtor.
Bool_t MakeCurrent()
If context is valid (TGLPaintDevice, for which context was created still exists), make it current.
void SetContext(TGLWidget *widget, const TGLContext *shareList)
X11 gl-context creation.
static void GlewInit()
Initialize GLEW - static private function.
TGLContext(TGLWidget *glWidget, Bool_t shareDefault=kTRUE, const TGLContext *shareList=0)
TGLContext ctor "from" TGLWidget.
Bool_t ClearCurrent()
Reset current context.
TGLContextIdentity * fIdentity
Definition TGLContext.h:43
TGLPaintDevice * fDevice
Definition TGLContext.h:37
static TGLContext * GetCurrent()
Ask TGLContextPrivate to lookup context in its internal map.
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 *.
Handle_t GetId() const
Definition TGObject.h:47
TOneArgGuard< Func, Arg > make_guard(Func f, Arg a)
Definition TGLUtil.h:1326