// @(#)root/gl:$Name: $:$Id: TGLDisplayListCache.cxx,v 1.12 2006/02/23 16:44:52 brun Exp $
// Author: Richard Maunder 25/05/2005
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
#include "TGLDisplayListCache.h"
#include "TGLDrawFlags.h"
#include "TGLUtil.h"
#include "TGLIncludes.h"
#include "Riostream.h"
#include "TError.h"
//////////////////////////////////////////////////////////////////////////
// //
// TGLDisplayListCache //
// //
// Singleton cache of GL display lists. Provides lazy automatic GL //
// display list capture of draws by a TGLDrawable at a certain 'LOD' //
// which can be disable on a global, per drawable or LOD basis. //
// //
// Internally the cache creates a block of GL display lists of fSize, //
// and maintains a stl::map, mapping CacheID_t ids (created from //
// TGLDrawable and LOD draw flag) to 'name' entries in the GL display //
// list block. //
// //
// See TGLDrawable::Draw() for use. //
// NOTE: Purging of individual TGLDrawables not currently implemented: //
// Purge(const TGLDrawable & drawable) //
// Purge(const TGLDrawable & drawable, UInt_t LOD) //
//////////////////////////////////////////////////////////////////////////
ClassImp(TGLDisplayListCache)
TGLDisplayListCache * TGLDisplayListCache::fgInstance = 0;
const UInt_t TGLDisplayListCache::fgInvalidDLName = 0;
//______________________________________________________________________________
TGLDisplayListCache & TGLDisplayListCache::Instance()
{
// Create (if required) and return the singleton display list cache
if (!fgInstance) {
fgInstance = new TGLDisplayListCache();
}
return *fgInstance;
}
//______________________________________________________________________________
TGLDisplayListCache::TGLDisplayListCache(Bool_t enable, UInt_t size) :
fSize(size), fInit(kFALSE), fEnabled(enable), fCaptureOpen(kFALSE),
fDLBase(fgInvalidDLName), fDLNextFree(fgInvalidDLName)
{
// Construct display list cache.
// Private constructor - cache is singleton obtained through
// TGLDisplayListCache::Instance()
}
//______________________________________________________________________________
TGLDisplayListCache::~TGLDisplayListCache()
{
// Destroy display list cache - deleting internal GL display list block
glDeleteLists(fDLBase,fSize);
}
//______________________________________________________________________________
void TGLDisplayListCache::Init()
{
// Initialise the cache - create the internal GL display list block of size
// fSize
fDLBase = glGenLists(fSize);
fDLNextFree = fDLBase;
TGLUtil::CheckError("TGLDisplayListCache::Init");
fInit = kTRUE;
}
//______________________________________________________________________________
Bool_t TGLDisplayListCache::Draw(const TGLDrawable & drawable, const TGLDrawFlags & flags) const
{
// Draw (call) the GL dislay list entry associated with the drawable / LOD
// flag pair, and return kTRUE. If no list item associated, return KFALSE.
if (!fEnabled) {
return kFALSE;
}
// TODO: Cache the lookup here ? As may have many calls of same draw/qual in a row
UInt_t drawList = Find(MakeCacheID(drawable, flags));
if (drawList == fgInvalidDLName) {
if (gDebug>4) {
Info("TGLDisplayListCache::Draw", "no cache for drawable %d LOD %d", &drawable, flags.LOD());
}
return kFALSE;
}
if (gDebug>4) {
Info("TGLDisplayListCache::Draw", "drawable %d LOD %d", &drawable, flags.LOD());
}
glCallList(drawList);
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGLDisplayListCache::OpenCapture(const TGLDrawable & drawable, const TGLDrawFlags & flags)
{
// Open capture of GL draw commands into cache entry, associated with
// drawable / LOD pair. Capture is done in GL_COMPILE mode - so the cache
// entry has to be drawn using TGLDisplayListCache::Draw() after capture close.
//
// Return kTRUE if opened, kFALSE if not. Capture is not opened if cache not
// enabled or cache if full.
// GL display lists can be nested at 'run' (draw) time, but cannot be nested
// in capture - so attempting to nest captures is rejected.
if (!fEnabled) {
return kFALSE;
}
if (fCaptureOpen) {
Error("TGLDisplayListCache::OpenCapture", "capture already ");
return(kFALSE);
}
// Cache full?
// TODO: Start to loop or recycle in another fashion?
if (fDLNextFree > fDLBase + fSize) {
Warning("TGLDisplayListCache::OpenCapture", "cache is full");
return kFALSE;
}
fCaptureOpen = kTRUE;
if (!fInit)
{
Init();
}
if (gDebug>4) {
Info("TGLDisplayListCache::OpenCapture", "for drawable %d LOD %d", &drawable, flags.LOD());
}
CacheID_t cacheID = MakeCacheID(drawable, flags);
fCacheDLMap.insert(CacheDLMap_t::value_type(cacheID,fDLNextFree));
//assert( Find(cacheID) == fDLNextFree );
glNewList(fDLNextFree,GL_COMPILE);
TGLUtil::CheckError("TGLDisplayListCache::OpenCapture");
fDLNextFree++;
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGLDisplayListCache::CloseCapture()
{
// Close currently open capture - return kTRUE if one open and successfully
// closed.
if (!fEnabled) {
return kFALSE;
}
if (!fCaptureOpen) {
Error("TGLDisplayListCache::CloseCapture", "no current capture open");
return kFALSE;
}
glEndList();
TGLUtil::CheckError("TGLDisplayListCache::CloseCapture");
fCaptureOpen = kFALSE;
if (gDebug>4) {
Info("TGLDisplayListCache::CloseCapture","complete");
}
return kTRUE;
}
//______________________________________________________________________________
void TGLDisplayListCache::Purge()
{
// Purge all entries for all drawable/LOD pairs from cache
glDeleteLists(fDLBase,fSize);
fCacheDLMap.erase(fCacheDLMap.begin(), fCacheDLMap.end());
fInit = kFALSE;
}
//______________________________________________________________________________
void TGLDisplayListCache::Purge(const TGLDrawable & /* drawable */)
{
// Purge all entries for a drawable at any LOD from cache
// NOTE: NOT IMPLEMENTED AT PRESENT!
if(fCaptureOpen) {
Error("TGLDisplayListCache::Purge", "attempt to purge while capture open");
return;
}
// TODO
}
//______________________________________________________________________________
void TGLDisplayListCache::Purge(const TGLDrawable & /* drawable */, const TGLDrawFlags & /* flags */)
{
// Purge entry for a drawable/LOD from cache
// NOTE: NOT IMPLEMENTED AT PRESENT!
if(fCaptureOpen) {
Error("TGLDisplayListCache::Purge", "attempt to purge while capture open");
return;
}
// TODO
}
//______________________________________________________________________________
UInt_t TGLDisplayListCache::Find(CacheID_t cacheID) const
{
// Return the GL display list block name associated with 'cacheID'
// cacheID is generated from drawable/flags pair - see
// TGLDisplayListCache::MakeCacheID()
CacheDLMap_t::const_iterator cacheDLMapIt;
cacheDLMapIt = fCacheDLMap.find(cacheID);
if (cacheDLMapIt != fCacheDLMap.end()) {
return (*cacheDLMapIt).second;
}
return fgInvalidDLName;
}
// TODO: Inline this
//______________________________________________________________________________
TGLDisplayListCache::CacheID_t TGLDisplayListCache::MakeCacheID(const TGLDrawable & drawable,
const TGLDrawFlags & flags) const
{
// Create a CacheID_t from drawable/flags pair provided.
// NOTE: Display Lists CAN capture GL state changes as well as geometry, but will
// not capture the current state set BEFORE the DL is opened.
// The CacheID_t returned is a std::pair<const TGLDrawable *, const UInt_t>,
// and used as key into fCacheDLMap - see TGLDisplayListCache::Find()
return CacheID_t(&drawable, flags.LOD());
}
//______________________________________________________________________________
void TGLDisplayListCache::Dump() const
{
// Dump usage count of cache
Info("TGLDisplayListCache::Dump", "%d of %d used", (fDLNextFree - fDLBase), fSize);
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.