TGLContext.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLContext.cxx 36675 2010-11-15 20:33:58Z matevz $
00002 // Author:  Timur Pocheptsov, Jun 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
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 // This class encapsulates window-system specific information about a
00035 // GL-context and alows their proper management in ROOT.
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    // TGLContext ctor "from" TGLWidget.
00051    // Is shareDefault is true, the shareList is set from default
00052    // context-identity. Otherwise the given shareList is used (can be
00053    // null).
00054    // Makes thread switching.
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    // Initialize GLEW - static private function.
00080    // Called immediately after creation of the first GL context.
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    //WIN32 gl-context creation. Defined as a member-function (this code removed from ctor)
00117    //to make WIN32/X11 separation cleaner.
00118    //This function is public only for calls via gROOT and called from ctor.
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    //Register context for "parent" gl-device.
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    //If context is valid (TGLPaintDevice, for which context was created still exists),
00163    //make it current.
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    //Reset current context.
00186    return wglMakeCurrent(0, 0);
00187 }
00188 
00189 //______________________________________________________________________________
00190 void TGLContext::SwapBuffers()
00191 {
00192    //If context is valid (TGLPaintDevice, for which context was created still exists),
00193    //swap buffers (in case of P-buffer call glFinish()).
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    //Make the context invalid and (do thread switch, if needed)
00213    //free resources.
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    //X11 gl-context creation. Defined as a member-function (this code removed from ctor)
00235    //to make WIN32/X11 separation cleaner.
00236    //This function is public only for calls via gROOT and called from ctor.
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    //If context is valid (TGLPaintDevice, for which context was created still exists),
00271    //make it current.
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    //Reset current context.
00296    return glXMakeCurrent(fPimpl->fDpy, None, 0);
00297 }
00298 
00299 //______________________________________________________________________________
00300 void TGLContext::SwapBuffers()
00301 {
00302    //If context is valid (TGLPaintDevice, for which context was created still exists),
00303    //swap buffers (in case of P-buffer call glFinish()).
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    //Make the context invalid and (do thread switch, if needed)
00320    //free resources.
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    //TGLContext dtor. If it's called before TGLPaintDevice's dtor
00334    //(context is valid) resource will be freed and context
00335    //un-registered.
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    //We can have several shared contexts,
00350    //and gl-scene wants to know, if some context
00351    //(defined by its identity) can be used.
00352    return fIdentity;
00353 }
00354 
00355 //______________________________________________________________________________
00356 TGLContext *TGLContext::GetCurrent()
00357 {
00358    //Ask TGLContextPrivate to lookup context in its internal map.
00359    return TGLContextPrivate::GetCurrentContext();
00360 }
00361 
00362 
00363 //______________________________________________________________________________
00364 //
00365 // Identifier of a shared GL-context.
00366 // Objects shared among GL-contexts include:
00367 // display-list definitions, texture objects and shader programs.
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    // Constructor.
00378 
00379 }
00380 
00381 //______________________________________________________________________________
00382 TGLContextIdentity::~TGLContextIdentity()
00383 {
00384    // Destructor.
00385 
00386    if (fFontManager) delete fFontManager;
00387 }
00388 
00389 //______________________________________________________________________________
00390 void TGLContextIdentity::AddRef(TGLContext* ctx)
00391 {
00392    //Add context ctx to the list of references.
00393    ++fCnt;
00394    fCtxs.push_back(ctx);
00395 }
00396 
00397 //______________________________________________________________________________
00398 void TGLContextIdentity::Release(TGLContext* ctx)
00399 {
00400    //Remove context ctx from the list of references.
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    //Remember dl range for deletion in next MakeCurrent or dtor execution.
00418    fDLTrash.push_back(DLRange_t(base, size));
00419 }
00420 
00421 //______________________________________________________________________________
00422 void TGLContextIdentity::DeleteGLResources()
00423 {
00424    //Delete GL resources registered for destruction.
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    //Find identitfy of current context. Static.
00441    TGLContext* ctx = TGLContext::GetCurrent();
00442    return ctx ? ctx->GetIdentity() : 0;
00443 }
00444 
00445 //______________________________________________________________________________
00446 TGLContextIdentity* TGLContextIdentity::GetDefaultIdentity()
00447 {
00448    //Get identity of a default Gl context. Static.
00449    if (fgDefaultIdentity == 0)
00450       fgDefaultIdentity = new TGLContextIdentity;
00451    return fgDefaultIdentity;
00452 }
00453 
00454 //______________________________________________________________________________
00455 TGLContext* TGLContextIdentity::GetDefaultContextAny()
00456 {
00457    //Get the first GL context with the default identity.
00458    //Can return zero, but that's OK, too. Static.
00459    if (fgDefaultIdentity == 0 || fgDefaultIdentity->fCtxs.empty())
00460       return 0;
00461    return fgDefaultIdentity->fCtxs.front();
00462 }
00463 
00464 //______________________________________________________________________________
00465 TGLFontManager* TGLContextIdentity::GetFontManager()
00466 {
00467    //Get the free-type font-manager associated with this context-identity.
00468    if(!fFontManager) fFontManager = new TGLFontManager();
00469    return fFontManager;
00470 }
00471 
00472 //______________________________________________________________________________
00473 void TGLContextIdentity::CheckDestroy()
00474 {
00475    //Private function called when reference count is reduced.
00476    if (fCnt <= 0 && fClientCnt <= 0)
00477    {
00478       if (this == fgDefaultIdentity)
00479          fgDefaultIdentity = 0;
00480       delete this;
00481    }
00482 }

Generated on Tue Jul 5 14:18:06 2011 for ROOT_528-00b_version by  doxygen 1.5.1