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 <memory>
13#include <stdexcept>
14#include <algorithm>
15#include <memory>
16
17#include "TVirtualX.h"
18#include "GuiTypes.h"
19#include "TString.h"
20#include "TError.h"
21
22#include "TROOT.h"
23#include "TVirtualMutex.h"
24
25#include "TGLContextPrivate.h"
26#include "RConfigure.h"
27#include "TGLIncludes.h"
28#include "TGLContext.h"
29#include "TGLWidget.h"
30#include "TGLFormat.h"
31#include "TGLUtil.h"
32
33#include "TGLFontManager.h"
34
35/** \class TGLContext
36\ingroup opengl
37This class encapsulates window-system specific information about a
38GL-context and alows their proper management in ROOT.
39*/
40
42
44
45////////////////////////////////////////////////////////////////////////////////
46/// TGLContext ctor "from" TGLWidget.
47/// Is shareDefault is true, the shareList is set from default
48/// context-identity. Otherwise the given shareList is used (can be
49/// null).
50/// Makes thread switching.
51
53 const TGLContext *shareList)
54 : fDevice(wid),
55 fFromCtor(kTRUE),
56 fValid(kFALSE),
57 fIdentity(nullptr)
58{
59 if (shareDefault)
61
62 if (!gVirtualX->IsCmdThread()) {
63 gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->SetContext((TGLWidget *)0x%zx, (TGLContext *)0x%zx)",
64 (size_t)this, (size_t)wid, (size_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
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
103namespace {
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
124void 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 fPimpl.reset(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}
164
165////////////////////////////////////////////////////////////////////////////////
166///If context is valid (TGLPaintDevice, for which context was created still exists),
167///make it current.
168
170{
171 if (!fValid) {
172 Error("TGLContext::MakeCurrent", "This context is invalid.");
173 return kFALSE;
174 }
175
176 if (!gVirtualX->IsCmdThread())
177 return Bool_t(gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->MakeCurrent()", (size_t)this)));
178 else {
179
181
182 Bool_t rez = wglMakeCurrent(fPimpl->fHDC, fPimpl->fGLContext);
183 if (rez) {
184 if (!fgGlewInitDone)
185 GlewInit();
187 }
188 return rez;
189 }
190}
191
192////////////////////////////////////////////////////////////////////////////////
193///Reset current context.
194
196{
197 return wglMakeCurrent(0, 0);
198}
199
200////////////////////////////////////////////////////////////////////////////////
201///If context is valid (TGLPaintDevice, for which context was created still exists),
202///swap buffers (in case of P-buffer call glFinish()).
203
205{
206 if (!fValid) {
207 Error("TGLContext::SwapBuffers", "This context is invalid.");
208 return;
209 }
210
211 if (!gVirtualX->IsCmdThread())
212 gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->SwapBuffers()", (size_t)this));
213 else {
214
216
217 if (fPimpl->fHWND)
218 wglSwapLayerBuffers(fPimpl->fHDC, WGL_SWAP_MAIN_PLANE);
219 else
220 glFinish();
221 }
222}
223
224////////////////////////////////////////////////////////////////////////////////
225///Make the context invalid and (do thread switch, if needed)
226///free resources.
227
229{
230 if (!gVirtualX->IsCmdThread()) {
231 gROOT->ProcessLineFast(Form("((TGLContext *)0x%zx)->Release()", (size_t)this));
232 return;
233 }
234
236
237 if (fPimpl->fHWND)
238 ReleaseDC(fPimpl->fHWND, fPimpl->fHDC);
239
241 wglDeleteContext(fPimpl->fGLContext);
242 fValid = kFALSE;
243}
244
245#elif defined(R__HAS_COCOA)
246
247////////////////////////////////////////////////////////////////////////////////
248///This function is public only for calls via gROOT and called from ctor.
249
250void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
251{
252 if (!fFromCtor) {
253 Error("TGLContext::SetContext", "SetContext must be called only from ctor");
254 return;
255 }
256
257 fPimpl.reset(new TGLContextPrivate);
258
259 fPimpl->fGLContext = gVirtualX->CreateOpenGLContext(widget->GetId(), shareList ? shareList->fPimpl->fGLContext : 0);
260 fPimpl->fWindowID = widget->GetId();
261
262 fValid = kTRUE;
263 fDevice->AddContext(this);
265}
266
267////////////////////////////////////////////////////////////////////////////////
268///If context is valid (TGLPaintDevice, for which context was created still exists),
269///make it current.
270
272{
273 if (!fValid) {
274 Error("TGLContext::MakeCurrent", "This context is invalid.");
275 return kFALSE;
276 }
277
278 const Bool_t rez = gVirtualX->MakeOpenGLContextCurrent(fPimpl->fGLContext, fPimpl->fWindowID);
279 if (rez) {
280 if (!fgGlewInitDone)
281 GlewInit();
283
284 }
285
286 return rez;
287}
288
289////////////////////////////////////////////////////////////////////////////////
290///Reset current context.
291
293{
294 return kFALSE;
295}
296
297////////////////////////////////////////////////////////////////////////////////
298///If context is valid (TGLPaintDevice, for which context was created still exists),
299///swap buffers (in case of P-buffer call glFinish()).
300
302{
303 if (!fValid) {
304 Error("TGLContext::SwapBuffers", "This context is invalid.");
305 return;
306 }
307
308 gVirtualX->FlushOpenGLBuffer(fPimpl->fGLContext);
309}
310
311////////////////////////////////////////////////////////////////////////////////
312///Make the context invalid and free resources.
313
315{
317 gVirtualX->DeleteOpenGLContext(fPimpl->fGLContext);
318 fValid = kFALSE;
319}
320
321//==============================================================================
322#else // X11
323//==============================================================================
324
325////////////////////////////////////////////////////////////////////////////////
326///X11 gl-context creation. Defined as a member-function (this code removed from ctor)
327///to make WIN32/X11 separation cleaner.
328///This function is public only for calls via gROOT and called from ctor.
329
330void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
331{
332 if (!fFromCtor) {
333 Error("TGLContext::SetContext", "SetContext must be called only from ctor");
334 return;
335 }
336
337 fPimpl = std::make_unique<TGLContextPrivate>();
338 Display *dpy = static_cast<Display *>(widget->GetInnerData().first);
339 XVisualInfo *visInfo = static_cast<XVisualInfo *>(widget->GetInnerData().second);
340
341 GLXContext glCtx = shareList ? glXCreateContext(dpy, visInfo, shareList->fPimpl->fGLContext, True)
342 : glXCreateContext(dpy, visInfo, None, True);
343
344 if (!glCtx) {
345 Error("TGLContext::SetContext", "glXCreateContext failed!");
346 throw std::runtime_error("glXCreateContext failed!");
347 }
348
349 fPimpl->fDpy = dpy;
350 fPimpl->fVisualInfo = visInfo;
351 fPimpl->fGLContext = glCtx;
352 fPimpl->fWindowID = widget->GetId();
353
354 fValid = kTRUE;
355 fDevice->AddContext(this);
357}
358
359////////////////////////////////////////////////////////////////////////////////
360///If context is valid (TGLPaintDevice, for which context was created still exists),
361///make it current.
362
364{
365 if (!fValid) {
366 Error("TGLContext::MakeCurrent", "This context is invalid.");
367 return kFALSE;
368 }
369
370 if (fPimpl->fWindowID != 0) {
371 const Bool_t rez = glXMakeCurrent(fPimpl->fDpy, fPimpl->fWindowID,
372 fPimpl->fGLContext);
373 if (rez) {
374 if (!fgGlewInitDone)
375 GlewInit();
377 }
378 return rez;
379 }
380
381 return kFALSE;
382}
383
384////////////////////////////////////////////////////////////////////////////////
385///Reset current context.
386
388{
389 return glXMakeCurrent(fPimpl->fDpy, None, nullptr);
390}
391
392////////////////////////////////////////////////////////////////////////////////
393///If context is valid (TGLPaintDevice, for which context was created still exists),
394///swap buffers (in case of P-buffer call glFinish()).
395
397{
398 if (!fValid) {
399 Error("TGLContext::SwapCurrent", "This context is invalid.");
400 return;
401 }
402
403 if (fPimpl->fWindowID != 0)
404 glXSwapBuffers(fPimpl->fDpy, fPimpl->fWindowID);
405 else
406 glFinish();
407}
408
409////////////////////////////////////////////////////////////////////////////////
410///Make the context invalid and (do thread switch, if needed)
411///free resources.
412
414{
416 glXDestroyContext(fPimpl->fDpy, fPimpl->fGLContext);
417 fValid = kFALSE;
418}
419
420//==============================================================================
421#endif
422//==============================================================================
423
424////////////////////////////////////////////////////////////////////////////////
425///TGLContext dtor. If it's called before TGLPaintDevice's dtor
426///(context is valid) resource will be freed and context
427///un-registered.
428
430{
431 if (fValid) {
432 Release();
433 fDevice->RemoveContext(this);
434 }
435
436 fIdentity->Release(this);
437}
438
439////////////////////////////////////////////////////////////////////////////////
440///We can have several shared contexts,
441///and gl-scene wants to know, if some context
442///(defined by its identity) can be used.
443
445{
446 return fIdentity;
447}
448
449////////////////////////////////////////////////////////////////////////////////
450///Ask TGLContextPrivate to lookup context in its internal map.
451
453{
455}
456
457
458/** \class TGLContextIdentity
459\ingroup opengl
460Identifier of a shared GL-context.
461Objects shared among GL-contexts include:
462display-list definitions, texture objects and shader programs.
463*/
464
466
468
469////////////////////////////////////////////////////////////////////////////////
470/// Constructor.
471
473fFontManager(nullptr), fCnt(0), fClientCnt(0)
474{
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// Destructor.
479
481{
482 if (fFontManager) delete fFontManager;
483}
484
485////////////////////////////////////////////////////////////////////////////////
486///Add context ctx to the list of references.
487
489{
490 ++fCnt;
491 fCtxs.push_back(ctx);
492}
493
494////////////////////////////////////////////////////////////////////////////////
495///Remove context ctx from the list of references.
496
498{
499 CtxList_t::iterator i = std::find(fCtxs.begin(), fCtxs.end(), ctx);
500 if (i != fCtxs.end())
501 {
502 fCtxs.erase(i);
503 --fCnt;
504 CheckDestroy();
505 }
506 else
507 {
508 Error("TGLContextIdentity::Release", "unregistered context.");
509 }
510}
511
512////////////////////////////////////////////////////////////////////////////////
513///Remember dl range for deletion in next MakeCurrent or dtor execution.
514
516{
517 fDLTrash.push_back(DLRange_t(base, size));
518}
519
520////////////////////////////////////////////////////////////////////////////////
521///Delete GL resources registered for destruction.
522
524{
525 if (!fDLTrash.empty())
526 {
527 for (DLTrashIt_t it = fDLTrash.begin(), e = fDLTrash.end(); it != e; ++it)
528 glDeleteLists(it->first, it->second);
529 fDLTrash.clear();
530 }
531
532 if (fFontManager)
534}
535
536////////////////////////////////////////////////////////////////////////////////
537///Find identitfy of current context. Static.
538
540{
542 return ctx ? ctx->GetIdentity() : nullptr;
543}
544
545////////////////////////////////////////////////////////////////////////////////
546///Get identity of a default Gl context. Static.
547
549{
550 if (fgDefaultIdentity == nullptr)
552 return fgDefaultIdentity;
553}
554
555////////////////////////////////////////////////////////////////////////////////
556///Get the first GL context with the default identity.
557///Can return zero, but that's OK, too. Static.
558
560{
561 if (fgDefaultIdentity == nullptr || fgDefaultIdentity->fCtxs.empty())
562 return nullptr;
563 return fgDefaultIdentity->fCtxs.front();
564}
565
566////////////////////////////////////////////////////////////////////////////////
567///Get the free-type font-manager associated with this context-identity.
568
570{
572 return fFontManager;
573}
574
575////////////////////////////////////////////////////////////////////////////////
576///Private function called when reference count is reduced.
577
579{
580 if (fCnt <= 0 && fClientCnt <= 0)
581 {
582 if (this == fgDefaultIdentity)
583 fgDefaultIdentity = nullptr;
584 delete this;
585 }
586}
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Definition RtypesCore.h:63
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
#define ClassImp(name)
Definition Rtypes.h:377
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:229
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize wid
Int_t gDebug
Definition TROOT.cxx:597
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:406
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
#define R__LOCKGUARD(mutex)
#define gVirtualX
Definition TVirtualX.h:337
void Stop() const
Definition TGLUtil.h:1286
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
TGLContext(TGLWidget *glWidget, Bool_t shareDefault=kTRUE, const TGLContext *shareList=nullptr)
TGLContext ctor "from" TGLWidget.
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.
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:41
TOneArgGuard< Func, Arg > make_guard(Func f, Arg a)
Definition TGLUtil.h:1329