00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <stdexcept>
00013 #include <algorithm>
00014 #include <memory>
00015
00016 #include "TVirtualX.h"
00017 #include "GuiTypes.h"
00018 #include "TString.h"
00019 #include "TError.h"
00020
00021 #include "TROOT.h"
00022
00023 #include "TGLContextPrivate.h"
00024 #include "TGLIncludes.h"
00025 #include "TGLContext.h"
00026 #include "TGLWidget.h"
00027 #include "TGLFormat.h"
00028 #include "TGLUtil.h"
00029
00030 #include "TGLFontManager.h"
00031
00032
00033
00034
00035
00036
00037 ClassImp(TGLContext);
00038
00039 Bool_t TGLContext::fgGlewInitDone = kFALSE;
00040
00041
00042 TGLContext::TGLContext(TGLWidget *wid, Bool_t shareDefault,
00043 const TGLContext *shareList)
00044 : fDevice(wid),
00045 fPimpl(0),
00046 fFromCtor(kTRUE),
00047 fValid(kFALSE),
00048 fIdentity(0)
00049 {
00050
00051
00052
00053
00054
00055
00056 if (shareDefault)
00057 shareList = TGLContextIdentity::GetDefaultContextAny();
00058
00059 if (!gVirtualX->IsCmdThread()) {
00060 gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SetContext((TGLWidget *)0x%lx, (TGLContext *)0x%lx)",
00061 (ULong_t)this, (ULong_t)wid, (ULong_t)shareList));
00062 } else {
00063 SetContext(wid, shareList);
00064 }
00065
00066 if (shareDefault)
00067 fIdentity = TGLContextIdentity::GetDefaultIdentity();
00068 else
00069 fIdentity = shareList ? shareList->GetIdentity() : new TGLContextIdentity;
00070
00071 fIdentity->AddRef(this);
00072
00073 fFromCtor = kFALSE;
00074 }
00075
00076
00077 void TGLContext::GlewInit()
00078 {
00079
00080
00081
00082 if (!fgGlewInitDone)
00083 {
00084 GLenum status = glewInit();
00085 if (status != GLEW_OK)
00086 Warning("TGLContext::GlewInit", "GLEW initalization failed.");
00087 else if (gDebug > 0)
00088 Info("TGLContext::GlewInit", "GLEW initalization successful.");
00089 fgGlewInitDone = kTRUE;
00090 }
00091 }
00092
00093
00094 #ifdef WIN32
00095
00096
00097 namespace {
00098
00099 struct LayoutCompatible_t {
00100 void *fDummy0;
00101 void *fDummy1;
00102 HWND *fPHwnd;
00103 unsigned char fDummy2;
00104 unsigned fDummy3;
00105 unsigned short fDummy4;
00106 unsigned short fDummy5;
00107 void *fDummy6;
00108 unsigned fDummy7:2;
00109 };
00110
00111 }
00112
00113
00114 void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
00115 {
00116
00117
00118
00119 if (!fFromCtor) {
00120 Error("TGLContext::SetContext", "SetContext must be called only from ctor");
00121 return;
00122 }
00123
00124 std::auto_ptr<TGLContextPrivate> safe_ptr(fPimpl = new TGLContextPrivate);
00125 LayoutCompatible_t *trick =
00126 reinterpret_cast<LayoutCompatible_t *>(widget->GetId());
00127 HWND hWND = *trick->fPHwnd;
00128 HDC hDC = GetWindowDC(hWND);
00129
00130 if (!hDC) {
00131 Error("TGLContext::SetContext", "GetWindowDC failed");
00132 throw std::runtime_error("GetWindowDC failed");
00133 }
00134
00135 const Rgl::TGuardBase &dcGuard = Rgl::make_guard(ReleaseDC, hWND, hDC);
00136 if (HGLRC glContext = wglCreateContext(hDC)) {
00137 if (shareList && !wglShareLists(shareList->fPimpl->fGLContext, glContext)) {
00138 wglDeleteContext(glContext);
00139 Error("TGLContext::SetContext", "Context sharing failed!");
00140 throw std::runtime_error("Context sharing failed");
00141 }
00142 fPimpl->fHWND = hWND;
00143 fPimpl->fHDC = hDC;
00144 fPimpl->fGLContext = glContext;
00145 } else {
00146 Error("TGLContext::SetContext", "wglCreateContext failed");
00147 throw std::runtime_error("wglCreateContext failed");
00148 }
00149
00150
00151 fValid = kTRUE;
00152 fDevice->AddContext(this);
00153 TGLContextPrivate::RegisterContext(this);
00154
00155 dcGuard.Stop();
00156 safe_ptr.release();
00157 }
00158
00159
00160 Bool_t TGLContext::MakeCurrent()
00161 {
00162
00163
00164 if (!fValid) {
00165 Error("TGLContext::MakeCurrent", "This context is invalid.");
00166 return kFALSE;
00167 }
00168
00169 if (!gVirtualX->IsCmdThread())
00170 return Bool_t(gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->MakeCurrent()", this)));
00171 else {
00172 Bool_t rez = wglMakeCurrent(fPimpl->fHDC, fPimpl->fGLContext);
00173 if (rez) {
00174 if (!fgGlewInitDone)
00175 GlewInit();
00176 fIdentity->DeleteGLResources();
00177 }
00178 return rez;
00179 }
00180 }
00181
00182
00183 Bool_t TGLContext::ClearCurrent()
00184 {
00185
00186 return wglMakeCurrent(0, 0);
00187 }
00188
00189
00190 void TGLContext::SwapBuffers()
00191 {
00192
00193
00194 if (!fValid) {
00195 Error("TGLContext::SwapBuffers", "This context is invalid.");
00196 return;
00197 }
00198
00199 if (!gVirtualX->IsCmdThread())
00200 gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->SwapBuffers()", this));
00201 else {
00202 if (fPimpl->fHWND)
00203 wglSwapLayerBuffers(fPimpl->fHDC, WGL_SWAP_MAIN_PLANE);
00204 else
00205 glFinish();
00206 }
00207 }
00208
00209
00210 void TGLContext::Release()
00211 {
00212
00213
00214 if (!gVirtualX->IsCmdThread()) {
00215 gROOT->ProcessLineFast(Form("((TGLContext *)0x%lx)->Release()", this));
00216 return;
00217 }
00218
00219 if (fPimpl->fHWND)
00220 ReleaseDC(fPimpl->fHWND, fPimpl->fHDC);
00221
00222 TGLContextPrivate::RemoveContext(this);
00223 wglDeleteContext(fPimpl->fGLContext);
00224 fValid = kFALSE;
00225 }
00226
00227
00228 #else // Non WIN32
00229
00230
00231
00232 void TGLContext::SetContext(TGLWidget *widget, const TGLContext *shareList)
00233 {
00234
00235
00236
00237
00238 if (!fFromCtor) {
00239 Error("TGLContext::SetContext", "SetContext must be called only from ctor");
00240 return;
00241 }
00242
00243 std::auto_ptr<TGLContextPrivate> safe_ptr(fPimpl = new TGLContextPrivate);
00244 Display *dpy = static_cast<Display *>(widget->GetInnerData().first);
00245 XVisualInfo *visInfo = static_cast<XVisualInfo *>(widget->GetInnerData().second);
00246
00247 GLXContext glCtx = shareList ? glXCreateContext(dpy, visInfo, shareList->fPimpl->fGLContext, True)
00248 : glXCreateContext(dpy, visInfo, None, True);
00249
00250 if (!glCtx) {
00251 Error("TGLContext::SetContext", "glXCreateContext failed!");
00252 throw std::runtime_error("glXCreateContext failed!");
00253 }
00254
00255 fPimpl->fDpy = dpy;
00256 fPimpl->fVisualInfo = visInfo;
00257 fPimpl->fGLContext = glCtx;
00258 fPimpl->fWindowID = widget->GetId();
00259
00260 fValid = kTRUE;
00261 fDevice->AddContext(this);
00262 TGLContextPrivate::RegisterContext(this);
00263
00264 safe_ptr.release();
00265 }
00266
00267
00268 Bool_t TGLContext::MakeCurrent()
00269 {
00270
00271
00272
00273 if (!fValid) {
00274 Error("TGLContext::MakeCurrent", "This context is invalid.");
00275 return kFALSE;
00276 }
00277
00278 if (fPimpl->fWindowID != 0) {
00279 const Bool_t rez = glXMakeCurrent(fPimpl->fDpy, fPimpl->fWindowID,
00280 fPimpl->fGLContext);
00281 if (rez) {
00282 if (!fgGlewInitDone)
00283 GlewInit();
00284 fIdentity->DeleteGLResources();
00285 }
00286 return rez;
00287 }
00288
00289 return kFALSE;
00290 }
00291
00292
00293 Bool_t TGLContext::ClearCurrent()
00294 {
00295
00296 return glXMakeCurrent(fPimpl->fDpy, None, 0);
00297 }
00298
00299
00300 void TGLContext::SwapBuffers()
00301 {
00302
00303
00304
00305 if (!fValid) {
00306 Error("TGLContext::SwapCurrent", "This context is invalid.");
00307 return;
00308 }
00309
00310 if (fPimpl->fWindowID != 0)
00311 glXSwapBuffers(fPimpl->fDpy, fPimpl->fWindowID);
00312 else
00313 glFinish();
00314 }
00315
00316
00317 void TGLContext::Release()
00318 {
00319
00320
00321 TGLContextPrivate::RemoveContext(this);
00322 glXDestroyContext(fPimpl->fDpy, fPimpl->fGLContext);
00323 fValid = kFALSE;
00324 }
00325
00326
00327 #endif
00328
00329
00330
00331 TGLContext::~TGLContext()
00332 {
00333
00334
00335
00336 if (fValid) {
00337 Release();
00338 fDevice->RemoveContext(this);
00339 }
00340
00341 fIdentity->Release(this);
00342
00343 delete fPimpl;
00344 }
00345
00346
00347 TGLContextIdentity *TGLContext::GetIdentity()const
00348 {
00349
00350
00351
00352 return fIdentity;
00353 }
00354
00355
00356 TGLContext *TGLContext::GetCurrent()
00357 {
00358
00359 return TGLContextPrivate::GetCurrentContext();
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369 ClassImp(TGLContextIdentity)
00370
00371 TGLContextIdentity* TGLContextIdentity::fgDefaultIdentity = new TGLContextIdentity;
00372
00373
00374 TGLContextIdentity::TGLContextIdentity():
00375 fFontManager(0), fCnt(0), fClientCnt(0)
00376 {
00377
00378
00379 }
00380
00381
00382 TGLContextIdentity::~TGLContextIdentity()
00383 {
00384
00385
00386 if (fFontManager) delete fFontManager;
00387 }
00388
00389
00390 void TGLContextIdentity::AddRef(TGLContext* ctx)
00391 {
00392
00393 ++fCnt;
00394 fCtxs.push_back(ctx);
00395 }
00396
00397
00398 void TGLContextIdentity::Release(TGLContext* ctx)
00399 {
00400
00401 CtxList_t::iterator i = std::find(fCtxs.begin(), fCtxs.end(), ctx);
00402 if (i != fCtxs.end())
00403 {
00404 fCtxs.erase(i);
00405 --fCnt;
00406 CheckDestroy();
00407 }
00408 else
00409 {
00410 Error("TGLContextIdentity::Release", "unregistered context.");
00411 }
00412 }
00413
00414
00415 void TGLContextIdentity::RegisterDLNameRangeToWipe(UInt_t base, Int_t size)
00416 {
00417
00418 fDLTrash.push_back(DLRange_t(base, size));
00419 }
00420
00421
00422 void TGLContextIdentity::DeleteGLResources()
00423 {
00424
00425
00426 if (!fDLTrash.empty())
00427 {
00428 for (DLTrashIt_t it = fDLTrash.begin(), e = fDLTrash.end(); it != e; ++it)
00429 glDeleteLists(it->first, it->second);
00430 fDLTrash.clear();
00431 }
00432
00433 if (fFontManager)
00434 fFontManager->ClearFontTrash();
00435 }
00436
00437
00438 TGLContextIdentity* TGLContextIdentity::GetCurrent()
00439 {
00440
00441 TGLContext* ctx = TGLContext::GetCurrent();
00442 return ctx ? ctx->GetIdentity() : 0;
00443 }
00444
00445
00446 TGLContextIdentity* TGLContextIdentity::GetDefaultIdentity()
00447 {
00448
00449 if (fgDefaultIdentity == 0)
00450 fgDefaultIdentity = new TGLContextIdentity;
00451 return fgDefaultIdentity;
00452 }
00453
00454
00455 TGLContext* TGLContextIdentity::GetDefaultContextAny()
00456 {
00457
00458
00459 if (fgDefaultIdentity == 0 || fgDefaultIdentity->fCtxs.empty())
00460 return 0;
00461 return fgDefaultIdentity->fCtxs.front();
00462 }
00463
00464
00465 TGLFontManager* TGLContextIdentity::GetFontManager()
00466 {
00467
00468 if(!fFontManager) fFontManager = new TGLFontManager();
00469 return fFontManager;
00470 }
00471
00472
00473 void TGLContextIdentity::CheckDestroy()
00474 {
00475
00476 if (fCnt <= 0 && fClientCnt <= 0)
00477 {
00478 if (this == fgDefaultIdentity)
00479 fgDefaultIdentity = 0;
00480 delete this;
00481 }
00482 }