Browse Source

simply geom caching system

David Rose 21 years ago
parent
commit
5ad57abaf5

+ 23 - 1
panda/src/display/colorMunger.cxx

@@ -97,5 +97,27 @@ compare_to_impl(const qpGeomMunger *other) const {
   if (_color_scale != om->_color_scale) {
   if (_color_scale != om->_color_scale) {
     return _color_scale < om->_color_scale ? -1 : 1;
     return _color_scale < om->_color_scale ? -1 : 1;
   }
   }
-  return 0;
+
+  return qpGeomMunger::compare_to_impl(other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorMunger::geom_compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int ColorMunger::
+geom_compare_to_impl(const qpGeomMunger *other) const {
+  const ColorMunger *om = DCAST(ColorMunger, other);
+  if (_color != om->_color) {
+    return _color < om->_color ? -1 : 1;
+  }
+  if (_color_scale != om->_color_scale) {
+    return _color_scale < om->_color_scale ? -1 : 1;
+  }
+
+  return qpGeomMunger::geom_compare_to_impl(other);
 }
 }

+ 1 - 0
panda/src/display/colorMunger.h

@@ -42,6 +42,7 @@ public:
 protected:
 protected:
   virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
   virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
   virtual int compare_to_impl(const qpGeomMunger *other) const;
   virtual int compare_to_impl(const qpGeomMunger *other) const;
+  virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
 
 
 private:
 private:
   int _num_components;
   int _num_components;

+ 4 - 3
panda/src/glstuff/glGeomMunger_src.cxx

@@ -84,6 +84,7 @@ compare_to_impl(const qpGeomMunger *other) const {
   if (_tex_gen != om->_tex_gen) {
   if (_tex_gen != om->_tex_gen) {
     return _tex_gen < om->_tex_gen ? -1 : 1;
     return _tex_gen < om->_tex_gen ? -1 : 1;
   }
   }
+
   return ColorMunger::compare_to_impl(other);
   return ColorMunger::compare_to_impl(other);
 }
 }
 
 
@@ -97,8 +98,8 @@ compare_to_impl(const qpGeomMunger *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int CLP(GeomMunger)::
 int CLP(GeomMunger)::
 geom_compare_to_impl(const qpGeomMunger *other) const {
 geom_compare_to_impl(const qpGeomMunger *other) const {
-  // We don't consider _texture and _tex_gen for these purposes; they
+  // We don't consider _texture and _tex_gen for this purpose; they
   // affect only whether the GL display list should be regenerated or
   // affect only whether the GL display list should be regenerated or
-  // not.
-  return ColorMunger::compare_to_impl(other);
+  // not, and don't require reconverting the vertices.
+  return ColorMunger::geom_compare_to_impl(other);
 }
 }

+ 17 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2057,6 +2057,11 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
     UpdateSeq modified = max(geom->get_modified(), _vertex_data->get_modified());
     UpdateSeq modified = max(geom->get_modified(), _vertex_data->get_modified());
     if (ggc->_modified == modified) {
     if (ggc->_modified == modified) {
       // If it hasn't been modified, just play the display list again.
       // If it hasn't been modified, just play the display list again.
+      if (GLCAT.is_spam()) {
+        GLCAT.spam()
+          << "calling display list " << ggc->_index << "\n";
+      }
+
       GLP(CallList)(ggc->_index);
       GLP(CallList)(ggc->_index);
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
       _vertices_display_list_pcollector.add_level(ggc->_num_verts);
       _vertices_display_list_pcollector.add_level(ggc->_num_verts);
@@ -2065,6 +2070,15 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
       // And now we don't need to do anything else for this geom.
       // And now we don't need to do anything else for this geom.
       return false;
       return false;
     }
     }
+    
+    if (GLCAT.is_debug()) {
+      GLCAT.debug()
+        << "compiling display list " << ggc->_index << "\n";
+      cerr << "ggc = " << ggc << "," << ggc->_modified
+           << " geom = " << geom << "," << geom->get_modified()
+           << " vertex_data = " << _vertex_data << "," 
+           << _vertex_data->get_modified() << "\n";
+    }
 
 
     // If it has been modified, or this is the first time, then we
     // If it has been modified, or this is the first time, then we
     // need to build the display list up.
     // need to build the display list up.
@@ -2149,15 +2163,18 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
         GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type), 
         GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type), 
                              stride, client_pointer + start);
                              stride, client_pointer + start);
         GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
         GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
+        cerr << "sending " << *name << "\n";
 
 
       } else {
       } else {
         // The vertex data doesn't have texcoords for this stage (even
         // The vertex data doesn't have texcoords for this stage (even
         // though they're needed).
         // though they're needed).
         GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
         GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
+        cerr << "not defined " << *name << "\n";
       }
       }
     } else {
     } else {
       // No texcoords are needed for this stage.
       // No texcoords are needed for this stage.
       GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
       GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
+      cerr << "not sending " << *stage->get_texcoord_name() << "\n";
     }
     }
 
 
     ++stage_index;
     ++stage_index;

+ 6 - 3
panda/src/gobj/Sources.pp

@@ -27,7 +27,8 @@
     qpgeomUsageHint.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
-    qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
+    qpgeomCacheEntry.h qpgeomCacheEntry.I \
+    qpgeomCacheManager.h qpgeomCacheManager.I \
     qpgeomVertexData.h qpgeomVertexData.I \
     qpgeomVertexData.h qpgeomVertexData.I \
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
@@ -63,7 +64,8 @@
     qpgeomTrifans.cxx \
     qpgeomTrifans.cxx \
     qpgeomVertexArrayData.cxx \
     qpgeomVertexArrayData.cxx \
     qpgeomVertexArrayFormat.cxx \
     qpgeomVertexArrayFormat.cxx \
-    qpgeomVertexCacheManager.cxx \
+    qpgeomCacheEntry.cxx \
+    qpgeomCacheManager.cxx \
     qpgeomVertexData.cxx \
     qpgeomVertexData.cxx \
     qpgeomVertexDataType.cxx \
     qpgeomVertexDataType.cxx \
     qpgeomVertexFormat.cxx \
     qpgeomVertexFormat.cxx \
@@ -97,7 +99,8 @@
     qpgeomUsageHint.h \
     qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
-    qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
+    qpgeomCacheEntry.h qpgeomCacheEntry.I \
+    qpgeomCacheManager.h qpgeomCacheManager.I \
     qpgeomVertexData.h qpgeomVertexData.I \
     qpgeomVertexData.h qpgeomVertexData.I \
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \

+ 2 - 1
panda/src/gobj/gobj_composite1.cxx

@@ -19,7 +19,8 @@
 #include "qpgeomTrifans.cxx"
 #include "qpgeomTrifans.cxx"
 #include "qpgeomVertexArrayData.cxx"
 #include "qpgeomVertexArrayData.cxx"
 #include "qpgeomVertexArrayFormat.cxx"
 #include "qpgeomVertexArrayFormat.cxx"
-#include "qpgeomVertexCacheManager.cxx"
+#include "qpgeomCacheEntry.cxx"
+#include "qpgeomCacheManager.cxx"
 #include "qpgeomVertexData.cxx"
 #include "qpgeomVertexData.cxx"
 #include "qpgeomVertexDataType.cxx"
 #include "qpgeomVertexDataType.cxx"
 #include "qpgeomVertexFormat.cxx"
 #include "qpgeomVertexFormat.cxx"

+ 22 - 0
panda/src/gobj/qpgeom.I

@@ -137,6 +137,28 @@ get_modified() const {
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CacheEntry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeom::CacheEntry::
+CacheEntry(const qpGeomMunger *modifier) :
+  _modifier(modifier)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CacheEntry::operator <
+//       Access: Public
+//  Description: Provides a unique ordering within the set.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeom::CacheEntry::
+operator < (const CacheEntry &other) const {
+  return (_modifier < other._modifier);
+}
+
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::CData::Constructor
 //     Function: qpGeom::CData::Constructor
 //       Access: Public
 //       Access: Public

+ 74 - 55
panda/src/gobj/qpgeom.cxx

@@ -17,7 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "qpgeom.h"
 #include "qpgeom.h"
-#include "qpgeomVertexCacheManager.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "bamWriter.h"
@@ -77,19 +76,17 @@ qpGeom::
   // When we destruct, we should ensure that all of our cached
   // When we destruct, we should ensure that all of our cached
   // entries, across all pipeline stages, are properly removed from
   // entries, across all pipeline stages, are properly removed from
   // the cache manager.
   // the cache manager.
-  qpGeomVertexCacheManager *cache_mgr = 
-    qpGeomVertexCacheManager::get_global_ptr();
-
   int num_stages = _cycler.get_num_stages();
   int num_stages = _cycler.get_num_stages();
   for (int i = 0; i < num_stages; i++) {
   for (int i = 0; i < num_stages; i++) {
     if (_cycler.is_stage_unique(i)) {
     if (_cycler.is_stage_unique(i)) {
       CData *cdata = _cycler.write_stage(i);
       CData *cdata = _cycler.write_stage(i);
-      for (MungedCache::iterator ci = cdata->_munged_cache.begin();
-           ci != cdata->_munged_cache.end();
+      for (Cache::iterator ci = cdata->_cache.begin();
+           ci != cdata->_cache.end();
            ++ci) {
            ++ci) {
-        cache_mgr->remove_geom(this, (*ci).first);
+        CacheEntry *entry = (*ci);
+        entry->erase();
       }
       }
-      cdata->_munged_cache.clear();
+      cdata->_cache.clear();
       _cycler.release_write_stage(i, cdata);
       _cycler.release_write_stage(i, cdata);
     }
     }
   }
   }
@@ -236,21 +233,22 @@ munge_geom(const qpGeomMunger *munger,
     // call to record_geom() might recursively call back into this
     // call to record_geom() might recursively call back into this
     // object, and require a write.
     // object, and require a write.
     const CData *cdata = _cycler.read();
     const CData *cdata = _cycler.read();
-    MungedCache::const_iterator ci = cdata->_munged_cache.find(munger);
-    if (ci != cdata->_munged_cache.end()) {
+    CacheEntry temp_entry(munger);
+    temp_entry.ref();  // big ugly hack to allow a static ReferenceCount object.
+    Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
+    if (ci != cdata->_cache.end()) {
       _cycler.release_read(cdata);
       _cycler.release_read(cdata);
+      CacheEntry *entry = (*ci);
+
       // Record a cache hit, so this element will stay in the cache a
       // Record a cache hit, so this element will stay in the cache a
       // while longer.
       // while longer.
-      qpGeomVertexCacheManager *cache_mgr = 
-        qpGeomVertexCacheManager::get_global_ptr();
-      cache_mgr->record_geom(this, munger, 
-                             (*ci).second._geom->get_num_bytes() +
-                             (*ci).second._data->get_num_bytes());
-
-      result = (*ci).second._geom;
-      data = (*ci).second._data;
+      entry->refresh();
+      result = entry->_geom_result;
+      data = entry->_data_result;
+      temp_entry.unref();
       return;
       return;
     }
     }
+    temp_entry.unref();
     _cycler.release_read(cdata);
     _cycler.release_read(cdata);
   }
   }
 
 
@@ -263,20 +261,21 @@ munge_geom(const qpGeomMunger *munger,
 
 
   {
   {
     // Record the new result in the cache.
     // Record the new result in the cache.
+    CacheEntry *entry;
     {
     {
       CDWriter cdata(((qpGeom *)this)->_cycler);
       CDWriter cdata(((qpGeom *)this)->_cycler);
-      MungeResult &mr = cdata->_munged_cache[munger];
-      mr._geom = result;
-      mr._data = data;
+      entry = new CacheEntry(munger);
+      entry->_source = (qpGeom *)this; 
+      entry->_geom_result = result;
+      entry->_data_result = data;
+      bool inserted = cdata->_cache.insert(entry).second;
+      nassertv(inserted);
     }
     }
     
     
     // And tell the cache manager about the new entry.  (It might
     // And tell the cache manager about the new entry.  (It might
-    // immediately request a delete from the cache of the thing we just
-    // added.)
-    qpGeomVertexCacheManager *cache_mgr = 
-      qpGeomVertexCacheManager::get_global_ptr();
-    cache_mgr->record_geom(this, munger, 
-                           result->get_num_bytes() + data->get_num_bytes());
+    // immediately request a delete from the cache of the thing we
+    // just added.)
+    entry->record();
   }
   }
 }
 }
 
 
@@ -334,16 +333,14 @@ void qpGeom::
 clear_cache() {
 clear_cache() {
   // Probably we shouldn't do anything at all here unless we are
   // Probably we shouldn't do anything at all here unless we are
   // running in pipeline stage 0.
   // running in pipeline stage 0.
-  qpGeomVertexCacheManager *cache_mgr = 
-    qpGeomVertexCacheManager::get_global_ptr();
-
   CData *cdata = CDWriter(_cycler);
   CData *cdata = CDWriter(_cycler);
-  for (MungedCache::iterator ci = cdata->_munged_cache.begin();
-       ci != cdata->_munged_cache.end();
+  for (Cache::iterator ci = cdata->_cache.begin();
+       ci != cdata->_cache.end();
        ++ci) {
        ++ci) {
-    cache_mgr->remove_geom(this, (*ci).first);
+    CacheEntry *entry = (*ci);
+    entry->erase();
   }
   }
-  cdata->_munged_cache.clear();
+  cdata->_cache.clear();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -473,27 +470,6 @@ recompute_bound() {
   return bound;
   return bound;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeom::remove_cache_entry
-//       Access: Private
-//  Description: Removes a particular entry from the local cache; it
-//               has already been removed from the cache manager.
-//               This is only called from GeomVertexCacheManager.
-////////////////////////////////////////////////////////////////////
-void qpGeom::
-remove_cache_entry(const qpGeomMunger *modifier) const {
-  // We have to operate on stage 0 of the pipeline, since that's where
-  // the cache really counts.  Because of the multistage pipeline, we
-  // might not actually have a cache entry there (it might have been
-  // added to stage 1 instead).  No big deal if we don't.
-  CData *cdata = ((qpGeom *)this)->_cycler.write_stage(0);
-  MungedCache::iterator ci = cdata->_munged_cache.find(modifier);
-  if (ci != cdata->_munged_cache.end()) {
-    cdata->_munged_cache.erase(ci);
-  }
-  ((qpGeom *)this)->_cycler.release_write_stage(0, cdata);
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::reset_usage_hint
 //     Function: qpGeom::reset_usage_hint
 //       Access: Private
 //       Access: Private
@@ -569,6 +545,49 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   manager->read_cdata(scan, _cycler);
   manager->read_cdata(scan, _cycler);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CacheEntry::evict_callback
+//       Access: Public, Virtual
+//  Description: Called when the entry is evicted from the cache, this
+//               should clean up the owning object appropriately.
+////////////////////////////////////////////////////////////////////
+void qpGeom::CacheEntry::
+evict_callback() {
+  // We have to operate on stage 0 of the pipeline, since that's where
+  // the cache really counts.  Because of the multistage pipeline, we
+  // might not actually have a cache entry there (it might have been
+  // added to stage 1 instead).  No big deal if we don't.
+  CData *cdata = _source->_cycler.write_stage(0);
+  Cache::iterator ci = cdata->_cache.find(this);
+  if (ci != cdata->_cache.end()) {
+    cdata->_cache.erase(ci);
+  }
+  _source->_cycler.release_write_stage(0, cdata);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CacheEntry::get_result_size
+//       Access: Public, Virtual
+//  Description: Returns the approximate number of bytes represented
+//               by the computed result.
+////////////////////////////////////////////////////////////////////
+int qpGeom::CacheEntry::
+get_result_size() const {
+  return _geom_result->get_num_bytes() + _data_result->get_num_bytes();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CacheEntry::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeom::CacheEntry::
+output(ostream &out) const {
+  out << "geom " << (void *)_source << ", " 
+      << (const void *)_modifier;
+}
+
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::CData::make_copy
 //     Function: qpGeom::CData::make_copy
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 18 - 9
panda/src/gobj/qpgeom.h

@@ -30,9 +30,12 @@
 #include "qpgeomPrimitive.h"
 #include "qpgeomPrimitive.h"
 #include "qpgeomMunger.h"
 #include "qpgeomMunger.h"
 #include "qpgeomUsageHint.h"
 #include "qpgeomUsageHint.h"
+#include "qpgeomCacheEntry.h"
 #include "updateSeq.h"
 #include "updateSeq.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "geom.h"
 #include "geom.h"
+#include "indirectLess.h"
+#include "pset.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : qpGeom
 //       Class : qpGeom
@@ -98,9 +101,6 @@ public:
 protected:
 protected:
   virtual BoundingVolume *recompute_bound();
   virtual BoundingVolume *recompute_bound();
 
 
-private:
-  void remove_cache_entry(const qpGeomMunger *modifier) const;
-
 private:
 private:
   typedef pvector<PT(qpGeomPrimitive) > Primitives;
   typedef pvector<PT(qpGeomPrimitive) > Primitives;
 
 
@@ -109,12 +109,21 @@ private:
   // cache needs to be stored in the CycleData, which makes accurate
   // cache needs to be stored in the CycleData, which makes accurate
   // cleanup more difficult.  We use the GeomVertexCacheManager class
   // cleanup more difficult.  We use the GeomVertexCacheManager class
   // to avoid cache bloat.
   // to avoid cache bloat.
-  class MungeResult {
+  class CacheEntry : public qpGeomCacheEntry {
   public:
   public:
-    CPT(qpGeom) _geom;
-    CPT(qpGeomVertexData) _data;
+    INLINE CacheEntry(const qpGeomMunger *modifier);
+    INLINE bool operator < (const CacheEntry &other) const;
+
+    virtual void evict_callback();
+    virtual int get_result_size() const;
+    virtual void output(ostream &out) const;
+
+    qpGeom *_source;
+    CPT(qpGeomMunger) _modifier;
+    CPT(qpGeom) _geom_result;
+    CPT(qpGeomVertexData) _data_result;
   };
   };
-  typedef pmap<CPT(qpGeomMunger), MungeResult> MungedCache;
+  typedef pset<PT(CacheEntry), IndirectLess<CacheEntry> > Cache;
 
 
   // This is the data that must be cycled between pipeline stages.
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
   class EXPCL_PANDA CData : public CycleData {
@@ -131,7 +140,7 @@ private:
     qpGeomUsageHint::UsageHint _usage_hint;
     qpGeomUsageHint::UsageHint _usage_hint;
     bool _got_usage_hint;
     bool _got_usage_hint;
     UpdateSeq _modified;
     UpdateSeq _modified;
-    MungedCache _munged_cache;
+    Cache _cache;
   };
   };
 
 
   PipelineCycler<CData> _cycler;
   PipelineCycler<CData> _cycler;
@@ -171,7 +180,7 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
-  friend class qpGeomVertexCacheManager;
+  friend class CacheEntry;
 };
 };
 
 
 INLINE ostream &operator << (ostream &out, const qpGeom &obj);
 INLINE ostream &operator << (ostream &out, const qpGeom &obj);

+ 93 - 0
panda/src/gobj/qpgeomCacheEntry.I

@@ -0,0 +1,93 @@
+// Filename: qpgeomCacheEntry.I
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomCacheEntry::
+qpGeomCacheEntry() {
+#ifndef NDEBUG
+  _next = NULL;
+  _prev = NULL;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::refresh
+//       Access: Public
+//  Description: Marks the cache entry recently used, so it will not
+//               be evicted for a while.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomCacheEntry::
+refresh() {
+  nassertv(_next != (qpGeomCacheEntry *)NULL && _prev != (qpGeomCacheEntry *)NULL);
+
+  qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
+  MutexHolder holder(cache_mgr->_lock);
+
+  remove_from_list();
+  insert_before(cache_mgr->_list);
+
+  int new_size = get_result_size();
+  cache_mgr->_total_size += (new_size - _result_size);
+  _result_size = new_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::remove_from_list
+//       Access: Private
+//  Description: Removes a GeomCacheEntry record from the
+//               doubly-linked list.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomCacheEntry::
+remove_from_list() {
+  nassertv(_prev->_next == this && _next->_prev == this);
+  _prev->_next = _next;
+  _next->_prev = _prev;
+#ifndef NDEBUG
+  _next = NULL;
+  _prev = NULL;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::insert_before
+//       Access: Private
+//  Description: Adds a GeomCacheEntry record before the indicated
+//               node in the doubly-linked list.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomCacheEntry::
+insert_before(qpGeomCacheEntry *node) {
+  nassertv(node->_prev->_next == node && node->_next->_prev == node);
+  nassertv(_prev == (qpGeomCacheEntry *)NULL &&
+           _next == (qpGeomCacheEntry *)NULL);
+  _prev = node->_prev;
+  _next = node;
+  _prev->_next = this;
+  node->_prev = this;
+}
+
+INLINE ostream &
+operator << (ostream &out, const qpGeomCacheEntry &entry) {
+  entry.output(out);
+  return out;
+}
+

+ 127 - 0
panda/src/gobj/qpgeomCacheEntry.cxx

@@ -0,0 +1,127 @@
+// Filename: qpgeomCacheEntry.cxx
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "qpgeomCacheEntry.h"
+#include "qpgeomCacheManager.h"
+#include "mutexHolder.h"
+#include "config_gobj.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomCacheEntry::
+~qpGeomCacheEntry() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::record
+//       Access: Public
+//  Description: Records the entry in the global cache for the first
+//               time.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomCacheEntry) qpGeomCacheEntry::
+record() {
+  nassertr(_next == (qpGeomCacheEntry *)NULL && _prev == (qpGeomCacheEntry *)NULL, NULL);
+  PT(qpGeomCacheEntry) keepme = this;
+
+  _result_size = get_result_size();
+
+  qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
+  MutexHolder holder(cache_mgr->_lock);
+
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "recording cache entry: " << *this << ", total_size = "
+      << cache_mgr->_total_size + _result_size << "\n";
+  }
+
+  insert_before(cache_mgr->_list);
+  cache_mgr->_total_size += _result_size;
+
+  // Increment our own reference count while we're in the queue, just
+  // so we don't have to play games with it later--this is inner-loop
+  // stuff.
+  ref();
+
+  // Now remove any old entries if our cache is over the limit.  This may
+  // also remove the entry we just added, especially if our cache size
+  // is set to 0.  This may actually remove this very object.
+  cache_mgr->evict_old_entries();
+
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::erase
+//       Access: Public
+//  Description: Removes the entry from the queue, returning a pointer
+//               to the entry.  Does not call evict_callback().
+////////////////////////////////////////////////////////////////////
+PT(qpGeomCacheEntry) qpGeomCacheEntry::
+erase() {
+  nassertr(_next != (qpGeomCacheEntry *)NULL && _prev != (qpGeomCacheEntry *)NULL, NULL);
+
+  PT(qpGeomCacheEntry) keepme = this;
+  unref();
+
+  if (gobj_cat.is_debug()) {
+    gobj_cat.debug()
+      << "remove_entry(" << *this << ")\n";
+  }
+
+  qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
+  MutexHolder holder(cache_mgr->_lock);
+
+  remove_from_list();
+  cache_mgr->_total_size -= _result_size;
+
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::evict_callback
+//       Access: Public, Virtual
+//  Description: Called when the entry is evicted from the cache, this
+//               should clean up the owning object appropriately.
+////////////////////////////////////////////////////////////////////
+void qpGeomCacheEntry::
+evict_callback() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::get_result_size
+//       Access: Public, Virtual
+//  Description: Returns the approximate number of bytes represented
+//               by the computed result.
+////////////////////////////////////////////////////////////////////
+int qpGeomCacheEntry::
+get_result_size() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheEntry::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomCacheEntry::
+output(ostream &out) const {
+  out << "[ unknown ]";
+}

+ 69 - 0
panda/src/gobj/qpgeomCacheEntry.h

@@ -0,0 +1,69 @@
+// Filename: qpgeomCacheEntry.h
+// Created by:  drose (21Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef qpGEOMCACHEENTRY_H
+#define qpGEOMCACHEENTRY_H
+
+#include "pandabase.h"
+#include "qpgeomCacheManager.h"
+#include "referenceCount.h"
+#include "config_gobj.h"
+#include "pointerTo.h"
+#include "mutexHolder.h"
+
+class qpGeom;
+class qpGeomPrimitive;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomCacheEntry
+// Description : This object contains a single cache entry in the
+//               GeomCacheManager.  This is actually the base class of
+//               any number of individual cache types.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomCacheEntry : public ReferenceCount {
+public:
+  INLINE qpGeomCacheEntry();
+  virtual ~qpGeomCacheEntry();
+
+  PT(qpGeomCacheEntry) record();
+  INLINE void refresh();
+  PT(qpGeomCacheEntry) erase();
+
+  virtual void evict_callback();
+  virtual int get_result_size() const;
+  virtual void output(ostream &out) const;
+
+private:
+  int _result_size;
+
+  INLINE void remove_from_list();
+  INLINE void insert_before(qpGeomCacheEntry *node);
+
+private:  
+  qpGeomCacheEntry *_prev, *_next;
+
+  friend class qpGeomCacheManager;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeomCacheEntry &entry);
+
+#include "qpgeomCacheEntry.I"
+
+#endif

+ 58 - 0
panda/src/gobj/qpgeomCacheManager.I

@@ -0,0 +1,58 @@
+// Filename: qpgeomCacheManager.I
+// Created by:  drose (11Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::set_max_size
+//       Access: Published
+//  Description: Specifies the amount of memory, in bytes, that should
+//               be set aside for storing pre-processed data for
+//               rendering vertices.  This is not a limit on the
+//               actual vertex data, which is what it is; it is also
+//               not a limit on the amount of memory used by the video
+//               driver or the system graphics interface, which Panda
+//               has no control over.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomCacheManager::
+set_max_size(int max_size) const {
+  // We directly change the config variable.
+  vertex_convert_cache = max_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::get_max_size
+//       Access: Published
+//  Description: Returns the amount of memory, in bytes, that should
+//               be set aside for storing pre-processed data for
+//               rendering vertices.  See set_max_size().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomCacheManager::
+get_max_size() const {
+  return vertex_convert_cache;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::get_total_size
+//       Access: Published
+//  Description: Returns the amount of memory, in bytes, currently
+//               consumed by the cache of pre-processed vertex data.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomCacheManager::
+get_total_size() const {
+  return _total_size;
+}

+ 92 - 0
panda/src/gobj/qpgeomCacheManager.cxx

@@ -0,0 +1,92 @@
+// Filename: qpgeomCacheManager.cxx
+// Created by:  drose (11Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "qpgeomCacheManager.h"
+#include "qpgeomCacheEntry.h"
+#include "mutexHolder.h"
+
+qpGeomCacheManager *qpGeomCacheManager::_global_ptr = NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomCacheManager::
+qpGeomCacheManager() :
+  _total_size(0)
+{
+  // We deliberately hang on to this pointer forever.
+  _list = new qpGeomCacheEntry;
+  _list->ref();
+  _list->_next = _list;
+  _list->_prev = _list;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::Destructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomCacheManager::
+~qpGeomCacheManager() {
+  // Shouldn't be deleting this global object.
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::get_global_ptr
+//       Access: Published, Static
+//  Description: Returns the global cache manager pointer.
+////////////////////////////////////////////////////////////////////
+qpGeomCacheManager *qpGeomCacheManager::
+get_global_ptr() {
+  if (_global_ptr == (qpGeomCacheManager *)NULL) {
+    _global_ptr = new qpGeomCacheManager;
+  }
+  return _global_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomCacheManager::evict_old_entries
+//       Access: Private
+//  Description: Trims the cache size down to get_max_size() by
+//               evicting old cache entries as needed.
+////////////////////////////////////////////////////////////////////
+void qpGeomCacheManager::
+evict_old_entries() {
+  MutexHolder holder(_lock);
+
+  int max_size = get_max_size();
+  while (_total_size > max_size) {
+    PT(qpGeomCacheEntry) entry = _list->_next;
+    nassertv(entry != _list);
+    entry->unref();
+
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "cache total_size = " << _total_size << ", max_size = "
+        << max_size << ", removing " << *entry << "\n";
+    }
+
+    entry->evict_callback();
+
+    _total_size -= entry->_result_size;
+    entry->remove_from_list();
+  }
+}

+ 91 - 0
panda/src/gobj/qpgeomCacheManager.h

@@ -0,0 +1,91 @@
+// Filename: qpgeomCacheManager.h
+// Created by:  drose (11Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef qpGEOMCACHEMANAGER_H
+#define qpGEOMCACHEMANAGER_H
+
+#include "pandabase.h"
+#include "config_gobj.h"
+#include "pmutex.h"
+
+class qpGeomCacheEntry;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomCacheManager
+// Description : This is used to keep track of, and limit the size of,
+//               the cache of munged vertices, which would otherwise
+//               be distributed through all of the GeomVertexData
+//               objects in the system.
+//
+//               The actual data in the cache is not stored here, but
+//               rather it is distributed among the various
+//               GeomVertexData source objects.  This allows the cache
+//               data to propagate through the multiprocess pipeline.
+//
+//               This structure actually caches any of a number of
+//               different types of pointers, and mixes them all up in
+//               the same LRU cache list.  Some of them (such as
+//               GeomMunger) are reference-counted here in the cache;
+//               most are not.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomCacheManager {
+protected:
+  qpGeomCacheManager();
+  ~qpGeomCacheManager();
+
+PUBLISHED:
+  INLINE void set_max_size(int max_size) const;
+  INLINE int get_max_size() const;
+
+  INLINE int get_total_size() const;
+
+  static qpGeomCacheManager *get_global_ptr();
+
+public:
+  void evict_old_entries();
+
+private:
+  // This mutex protects all operations on this object, especially the
+  // linked-list operations.
+  Mutex _lock;
+
+  int _total_size;
+
+  // We maintain a doubly-linked list to keep the cache entries in
+  // least-recently-used order: the items at the head of the list are
+  // ready to be flushed.  We use our own doubly-linked list instead
+  // of an STL list, just so we can avoid a tiny bit of overhead,
+  // especially in keeping the pointer directly into the list from the
+  // calling objects.
+
+  // The tail and the head of the list are both kept by the _prev and
+  // _next pointers, respectively, within the following object, which
+  // always exists solely to keep a handle to the list.  Keeping a
+  // token of the list this way avoids special cases for an empty
+  // list.
+  qpGeomCacheEntry *_list;
+
+  static qpGeomCacheManager *_global_ptr;
+  friend class qpGeomCacheEntry;
+};
+
+#include "qpgeomCacheManager.I"
+
+#endif

+ 53 - 8
panda/src/gobj/qpgeomMunger.cxx

@@ -17,7 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "qpgeomMunger.h"
 #include "qpgeomMunger.h"
-#include "qpgeomVertexCacheManager.h"
+#include "qpgeomCacheManager.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 
 
@@ -35,6 +35,29 @@ qpGeomMunger::
 qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) :
 qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) :
   _is_registered(false)
   _is_registered(false)
 {
 {
+  _registered_key = get_registry()->_mungers.end();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomMunger::
+qpGeomMunger(const qpGeomMunger &copy) :
+  _is_registered(false)
+{
+  _registered_key = get_registry()->_mungers.end();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+operator = (const qpGeomMunger &copy) {
+  nassertv(!_is_registered);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -205,7 +228,7 @@ compare_to_impl(const qpGeomMunger *other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int qpGeomMunger::
 int qpGeomMunger::
 geom_compare_to_impl(const qpGeomMunger *other) const {
 geom_compare_to_impl(const qpGeomMunger *other) const {
-  return compare_to_impl(other);
+  return 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -237,9 +260,9 @@ do_register() {
   // Tell the cache manager to hang on to this new GeomMunger, so we
   // Tell the cache manager to hang on to this new GeomMunger, so we
   // don't waste our time re-registering the same GeomMunger over and
   // don't waste our time re-registering the same GeomMunger over and
   // over again.
   // over again.
-  qpGeomVertexCacheManager *cache_mgr =
-    qpGeomVertexCacheManager::get_global_ptr();
-  cache_mgr->record_munger(this);
+  CacheEntry *entry = new CacheEntry;
+  entry->_munger = this;
+  entry->record();
 
 
   _is_registered = true;
   _is_registered = true;
 }
 }
@@ -277,6 +300,27 @@ do_unregister() {
   _formats.clear();
   _formats.clear();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::CacheEntry::get_result_size
+//       Access: Public, Virtual
+//  Description: Returns the approximate number of bytes represented
+//               by the computed result.
+////////////////////////////////////////////////////////////////////
+int qpGeomMunger::CacheEntry::
+get_result_size() const {
+  return sizeof(qpGeomMunger);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::CacheEntry::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::CacheEntry::
+output(ostream &out) const {
+  out << "munger " << _munger;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomMunger::Registry::Constructor
 //     Function: qpGeomMunger::Registry::Constructor
 //       Access: Public
 //       Access: Public
@@ -315,6 +359,7 @@ register_munger(qpGeomMunger *munger) {
   Mungers::iterator mi = _mungers.insert(munger).first;
   Mungers::iterator mi = _mungers.insert(munger).first;
   qpGeomMunger *new_munger = (*mi);
   qpGeomMunger *new_munger = (*mi);
   if (!new_munger->is_registered()) {
   if (!new_munger->is_registered()) {
+    new_munger->_registered_key = mi;
     new_munger->do_register();
     new_munger->do_register();
   }
   }
 
 
@@ -331,8 +376,8 @@ register_munger(qpGeomMunger *munger) {
 void qpGeomMunger::Registry::
 void qpGeomMunger::Registry::
 unregister_munger(qpGeomMunger *munger) {
 unregister_munger(qpGeomMunger *munger) {
   nassertv(munger->is_registered());
   nassertv(munger->is_registered());
-  Mungers::iterator mi = _mungers.find(munger);
-  nassertv(mi != _mungers.end());
-  _mungers.erase(mi);
+  nassertv(munger->_registered_key != _mungers.end());
+  _mungers.erase(munger->_registered_key);
+  munger->_registered_key = _mungers.end();
   munger->do_unregister();
   munger->do_unregister();
 }
 }

+ 20 - 0
panda/src/gobj/qpgeomMunger.h

@@ -23,6 +23,7 @@
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
 #include "qpgeomVertexFormat.h"
 #include "qpgeomVertexFormat.h"
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexData.h"
+#include "qpgeomCacheEntry.h"
 #include "indirectCompareTo.h"
 #include "indirectCompareTo.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
@@ -59,6 +60,8 @@ class qpGeom;
 class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount {
 class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount {
 public:
 public:
   qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state);
   qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state);
+  qpGeomMunger(const qpGeomMunger &copy);
+  void operator = (const qpGeomMunger &copy);
   virtual ~qpGeomMunger();
   virtual ~qpGeomMunger();
 
 
   INLINE bool is_registered() const;
   INLINE bool is_registered() const;
@@ -94,6 +97,14 @@ private:
   void do_unregister();
   void do_unregister();
 
 
 private:
 private:
+  class CacheEntry : public qpGeomCacheEntry {
+  public:
+    virtual int get_result_size() const;
+    virtual void output(ostream &out) const;
+
+    PT(qpGeomMunger) _munger;
+  };
+
   typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
   typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
   Formats _formats;
   Formats _formats;
 
 
@@ -108,6 +119,15 @@ private:
     Mungers _mungers;
     Mungers _mungers;
   };
   };
 
 
+  // We store the iterator into the above registry, while we are
+  // registered.  This makes it easier to remove our own entry,
+  // especially when the destructor is called.  Since it's a virtual
+  // destructor, we can't reliably look up our pointer in the map once
+  // we have reached the base class destructor (since the object has
+  // changed types by then, and the sorting in the map depends partly
+  // on type).
+  Mungers::iterator _registered_key;
+
   static Registry *_registry;
   static Registry *_registry;
 
 
   static PStatCollector _munge_pcollector;
   static PStatCollector _munge_pcollector;

+ 58 - 41
panda/src/gobj/qpgeomPrimitive.cxx

@@ -21,7 +21,6 @@
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexDataType.h"
 #include "qpgeomVertexDataType.h"
-#include "qpgeomVertexCacheManager.h"
 #include "preparedGraphicsObjects.h"
 #include "preparedGraphicsObjects.h"
 #include "internalName.h"
 #include "internalName.h"
 #include "bamReader.h"
 #include "bamReader.h"
@@ -66,16 +65,13 @@ qpGeomPrimitive::
   // When we destruct, we should ensure that all of our cached
   // When we destruct, we should ensure that all of our cached
   // entries, across all pipeline stages, are properly removed from
   // entries, across all pipeline stages, are properly removed from
   // the cache manager.
   // the cache manager.
-  qpGeomVertexCacheManager *cache_mgr = 
-    qpGeomVertexCacheManager::get_global_ptr();
-
   int num_stages = _cycler.get_num_stages();
   int num_stages = _cycler.get_num_stages();
   for (int i = 0; i < num_stages; i++) {
   for (int i = 0; i < num_stages; i++) {
     if (_cycler.is_stage_unique(i)) {
     if (_cycler.is_stage_unique(i)) {
       CData *cdata = _cycler.write_stage(i);
       CData *cdata = _cycler.write_stage(i);
-      if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
-        cache_mgr->remove_primitive(this);
-        cdata->_decomposed = NULL;
+      if (cdata->_cache != (CacheEntry *)NULL) {
+        cdata->_cache->erase();
+        cdata->_cache = NULL;
       }
       }
       _cycler.release_write_stage(i, cdata);
       _cycler.release_write_stage(i, cdata);
     }
     }
@@ -446,14 +442,12 @@ decompose() const {
     // call to record_primitive() might recursively call back into
     // call to record_primitive() might recursively call back into
     // this object, and require a write.
     // this object, and require a write.
     const CData *cdata = _cycler.read();
     const CData *cdata = _cycler.read();
-    if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
-      result = cdata->_decomposed;
+    if (cdata->_cache != (CacheEntry *)NULL) {
+      result = cdata->_cache->_decomposed;
       _cycler.release_read(cdata);
       _cycler.release_read(cdata);
       // Record a cache hit, so this element will stay in the cache a
       // Record a cache hit, so this element will stay in the cache a
       // while longer.
       // while longer.
-      qpGeomVertexCacheManager *cache_mgr = 
-        qpGeomVertexCacheManager::get_global_ptr();
-      cache_mgr->record_primitive(this, result->get_num_bytes());
+      cdata->_cache->refresh();
 
 
       return result;
       return result;
     }
     }
@@ -472,13 +466,17 @@ decompose() const {
   }
   }
 
 
   // Record the result for the future.
   // Record the result for the future.
-  CDWriter cdata(((qpGeomPrimitive *)this)->_cycler);
-  cdata->_decomposed = result;
+  CacheEntry *entry;
+  {
+    CDWriter cdata(((qpGeomPrimitive *)this)->_cycler);
+    entry = new CacheEntry;
+    entry->_source = (qpGeomPrimitive *)this;
+    entry->_decomposed = result;
+    cdata->_cache = entry;
+  }
 
 
   // And add *this* object to the cache manager.
   // And add *this* object to the cache manager.
-  qpGeomVertexCacheManager *cache_mgr = 
-    qpGeomVertexCacheManager::get_global_ptr();
-  cache_mgr->record_primitive(this, result->get_num_bytes());
+  entry->record();
 
 
   return result;
   return result;
 }
 }
@@ -526,13 +524,10 @@ void qpGeomPrimitive::
 clear_cache() {
 clear_cache() {
   // Probably we shouldn't do anything at all here unless we are
   // Probably we shouldn't do anything at all here unless we are
   // running in pipeline stage 0.
   // running in pipeline stage 0.
-  qpGeomVertexCacheManager *cache_mgr = 
-    qpGeomVertexCacheManager::get_global_ptr();
-
   CData *cdata = CDWriter(_cycler);
   CData *cdata = CDWriter(_cycler);
-  if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
-    cache_mgr->remove_primitive(this);
-    cdata->_decomposed = NULL;
+  if (cdata->_cache != (CacheEntry *)NULL) {
+    cdata->_cache->erase();
+    cdata->_cache = NULL;
   }
   }
 
 
   // This, on the other hand, should be applied to the current
   // This, on the other hand, should be applied to the current
@@ -779,24 +774,6 @@ do_rotate() {
   cdataw->_rotated_vertices = rotated_vertices;
   cdataw->_rotated_vertices = rotated_vertices;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::remove_cache_entry
-//       Access: Private
-//  Description: Removes a particular entry from the local cache; it
-//               has already been removed from the cache manager.
-//               This is only called from GeomVertexCacheManager.
-////////////////////////////////////////////////////////////////////
-void qpGeomPrimitive::
-remove_cache_entry() const {
-  // We have to operate on stage 0 of the pipeline, since that's where
-  // the cache really counts.  Because of the multistage pipeline, we
-  // might not actually have a cache entry there (it might have been
-  // added to stage 1 instead).  No big deal if we don't.
-  CData *cdata = ((qpGeomPrimitive *)this)->_cycler.write_stage(0);
-  cdata->_decomposed = NULL;
-  ((qpGeomPrimitive *)this)->_cycler.release_write_stage(0, cdata);
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::recompute_minmax
 //     Function: qpGeomPrimitive::recompute_minmax
 //       Access: Private
 //       Access: Private
@@ -896,6 +873,46 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   manager->read_cdata(scan, _cycler);
   manager->read_cdata(scan, _cycler);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CacheEntry::evict_callback
+//       Access: Public, Virtual
+//  Description: Called when the entry is evicted from the cache, this
+//               should clean up the owning object appropriately.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::CacheEntry::
+evict_callback() {
+  // We have to operate on stage 0 of the pipeline, since that's where
+  // the cache really counts.  Because of the multistage pipeline, we
+  // might not actually have a cache entry there (it might have been
+  // added to stage 1 instead).  No big deal if we don't.
+  CData *cdata = _source->_cycler.write_stage(0);
+  if (cdata->_cache == this) {
+    cdata->_cache = NULL;
+  }
+  _source->_cycler.release_write_stage(0, cdata);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CacheEntry::get_result_size
+//       Access: Public, Virtual
+//  Description: Returns the approximate number of bytes represented
+//               by the computed result.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::CacheEntry::
+get_result_size() const {
+  return _decomposed->get_num_bytes();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CacheEntry::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::CacheEntry::
+output(ostream &out) const {
+  out << "primitive " << (void *)_source;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::CData::make_copy
 //     Function: qpGeomPrimitive::CData::make_copy
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 13 - 3
panda/src/gobj/qpgeomPrimitive.h

@@ -21,6 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "qpgeomUsageHint.h"
 #include "qpgeomUsageHint.h"
+#include "qpgeomCacheEntry.h"
 #include "typedWritableReferenceCount.h"
 #include "typedWritableReferenceCount.h"
 #include "luse.h"
 #include "luse.h"
 #include "updateSeq.h"
 #include "updateSeq.h"
@@ -163,7 +164,6 @@ protected:
 
 
 private: 
 private: 
   void do_rotate();
   void do_rotate();
-  void remove_cache_entry() const;
 
 
 protected:
 protected:
   static PStatCollector _rotate_pcollector;
   static PStatCollector _rotate_pcollector;
@@ -179,6 +179,17 @@ private:
   typedef pmap<PreparedGraphicsObjects *, IndexBufferContext *> Contexts;
   typedef pmap<PreparedGraphicsObjects *, IndexBufferContext *> Contexts;
   Contexts _contexts;
   Contexts _contexts;
 
 
+  class CacheEntry : public qpGeomCacheEntry {
+  public:
+    virtual void evict_callback();
+    virtual int get_result_size() const;
+    virtual void output(ostream &out) const;
+
+    qpGeomPrimitive *_source;
+    CPT(qpGeomPrimitive) _decomposed;
+  };
+    
+
   // This is the data that must be cycled between pipeline stages.
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
   class EXPCL_PANDA CData : public CycleData {
   public:
   public:
@@ -201,7 +212,7 @@ private:
     unsigned short _min_vertex;
     unsigned short _min_vertex;
     unsigned short _max_vertex;
     unsigned short _max_vertex;
 
 
-    CPT(qpGeomPrimitive) _decomposed;
+    PT(CacheEntry) _cache;
   };
   };
 
 
   PipelineCycler<CData> _cycler;
   PipelineCycler<CData> _cycler;
@@ -234,7 +245,6 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
   friend class qpGeom;
   friend class qpGeom;
-  friend class qpGeomVertexCacheManager;
   friend class PreparedGraphicsObjects;
   friend class PreparedGraphicsObjects;
 };
 };
 
 

+ 1 - 1
panda/src/gobj/qpgeomVertexArrayData.h

@@ -141,7 +141,7 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
-  friend class qpGeomVertexCacheManager;
+  friend class qpGeomCacheManager;
   friend class PreparedGraphicsObjects;
   friend class PreparedGraphicsObjects;
 };
 };
 
 

+ 0 - 303
panda/src/gobj/qpgeomVertexCacheManager.I

@@ -1,303 +0,0 @@
-// Filename: qpgeomVertexCacheManager.I
-// Created by:  drose (11Mar05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::set_max_size
-//       Access: Published
-//  Description: Specifies the amount of memory, in bytes, that should
-//               be set aside for storing pre-processed data for
-//               rendering vertices.  This is not a limit on the
-//               actual vertex data, which is what it is; it is also
-//               not a limit on the amount of memory used by the video
-//               driver or the system graphics interface, which Panda
-//               has no control over.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-set_max_size(int max_size) const {
-  // We directly change the config variable.
-  vertex_convert_cache = max_size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::get_max_size
-//       Access: Published
-//  Description: Returns the amount of memory, in bytes, that should
-//               be set aside for storing pre-processed data for
-//               rendering vertices.  See set_max_size().
-////////////////////////////////////////////////////////////////////
-INLINE int qpGeomVertexCacheManager::
-get_max_size() const {
-  return vertex_convert_cache;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::get_total_size
-//       Access: Published
-//  Description: Returns the amount of memory, in bytes, currently
-//               consumed by the cache of pre-processed vertex data.
-////////////////////////////////////////////////////////////////////
-INLINE int qpGeomVertexCacheManager::
-get_total_size() const {
-  return _total_size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::record_munger
-//       Access: Private
-//  Description: Records a new GeomMunger in the cache, or marks a
-//               cache hit for a previously-recorded munger.  This
-//               should only be called by GeomMunger.
-//
-//               The cache manager will hold a reference on the
-//               GeomMunger pointer until it expires from the cache.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-record_munger(const qpGeomMunger *munger) {
-  // Make up a nominal result_size for a munger.
-  record_entry(Entry(munger, 100));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::record_primitive
-//       Access: Private
-//  Description: Records a new entry in the cache, or marks a cache
-//               hit for a previous entry in the cache.  This should
-//               only be called by GeomPrimitive.
-//
-//               The cache manager will not hold a reference on the
-//               GeomPrimitive pointer; if it destructs, it should
-//               call remove_primitive() to remove itself from the cache.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-record_primitive(const qpGeomPrimitive *primitive, int result_size) {
-  record_entry(Entry(primitive, result_size));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::remove_primitive
-//       Access: Private
-//  Description: Removes an entry from the cache, if it is there.
-//               Quietly ignores it if it is not.  This should only be
-//               called by GeomPrimitive.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-remove_primitive(const qpGeomPrimitive *primitive) {
-  remove_entry(Entry(primitive, 0));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::record_geom
-//       Access: Private
-//  Description: Records a new entry in the cache, or marks a cache
-//               hit for a previous entry in the cache.  This should
-//               only be called by Geom.
-//
-//               The cache manager will not hold a reference on the
-//               Geom pointer; if it destructs, it should call
-//               remove_geom() to remove itself from the cache.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-record_geom(const qpGeom *source, const qpGeomMunger *modifier,
-            int result_size) {
-  record_entry(Entry(source, modifier, result_size));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::remove_geom
-//       Access: Private
-//  Description: Removes an entry from the cache, if it is there.
-//               Quietly ignores it if it is not.  This should only be
-//               called by GeomVertexData.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-remove_geom(const qpGeom *source, const qpGeomMunger *modifier) {
-  remove_entry(Entry(source, modifier, 0));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::dequeue_entry
-//       Access: Private
-//  Description: Removes an Entry record from the doubly-linked list.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-dequeue_entry(qpGeomVertexCacheManager::Entry *entry) {
-  nassertv(entry->_prev->_next == entry &&
-           entry->_next->_prev == entry);
-  entry->_prev->_next = entry->_next;
-  entry->_next->_prev = entry->_prev;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::enqueue_entry
-//       Access: Private
-//  Description: Adds an Entry record to the tail of the doubly-linked
-//               list.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::
-enqueue_entry(qpGeomVertexCacheManager::Entry *entry) {
-  nassertv(_list->_prev->_next == _list &&
-           _list->_next->_prev == _list);
-  entry->_prev = _list->_prev;
-  entry->_next = _list;
-  entry->_prev->_next = entry;
-  _list->_prev = entry;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-Entry() :
-  _cache_type(CT_none),
-  _result_size(0)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-Entry(const qpGeomMunger *munger, int result_size) :
-  _cache_type(CT_munger),
-  _result_size(result_size)
-{
-  _u._munger = munger;
-  _u._munger->ref();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-Entry(const qpGeomPrimitive *primitive, int result_size) :
-  _cache_type(CT_primitive),
-  _result_size(result_size)
-{
-  _u._primitive = primitive;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-Entry(const qpGeom *source, const qpGeomMunger *modifier,
-      int result_size) :
-  _cache_type(CT_geom),
-  _result_size(result_size)
-{
-  _u._geom._source = source;
-  _u._geom._modifier = modifier;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Copy Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-Entry(const qpGeomVertexCacheManager::Entry &copy) :
-  _cache_type(copy._cache_type),
-  _result_size(copy._result_size)
-{
-  _u = copy._u;
-  if (_cache_type == CT_munger) {
-    _u._munger->ref();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Copy Assignment Operator
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeomVertexCacheManager::Entry::
-operator = (const qpGeomVertexCacheManager::Entry &copy) {
-  if (_cache_type == CT_munger) {
-    unref_delete(_u._munger);
-  }
-  _cache_type = copy._cache_type;
-  _result_size = copy._result_size;
-  _u = copy._u;
-  if (_cache_type == CT_munger) {
-    _u._munger->ref();
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::Destructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexCacheManager::Entry::
-~Entry() {
-  if (_cache_type == CT_munger) {
-    unref_delete(_u._munger);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::operator <
-//       Access: Public
-//  Description: Provides a unique ordering for EntriesIndex.
-////////////////////////////////////////////////////////////////////
-INLINE bool qpGeomVertexCacheManager::Entry::
-operator < (const qpGeomVertexCacheManager::Entry &other) const {
-  if (_cache_type != other._cache_type) {
-    return (int)_cache_type < (int)other._cache_type;
-  }
-
-  switch (_cache_type) {
-  case CT_none:
-    // We shouldn't be adding the end-of-list token to the index.
-    nassertr(false, false);
-    return false;
-
-  case CT_munger:
-    return _u._munger < other._u._munger;
-
-  case CT_primitive:
-    return _u._primitive < other._u._primitive;
-
-  case CT_geom:
-    if (_u._geom._source != other._u._geom._source) {
-      return _u._geom._source < other._u._geom._source;
-    }
-    if (_u._geom._modifier != other._u._geom._modifier) {
-      return _u._geom._modifier->geom_compare_to(*other._u._geom._modifier) < 0;
-    }
-    return 0;
-  }
-
-  return false;
-}
-
-INLINE ostream &
-operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry) {
-  entry.output(out);
-  return out;
-}
-

+ 0 - 196
panda/src/gobj/qpgeomVertexCacheManager.cxx

@@ -1,196 +0,0 @@
-// Filename: qpgeomVertexCacheManager.cxx
-// Created by:  drose (11Mar05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "qpgeomVertexCacheManager.h"
-#include "mutexHolder.h"
-
-qpGeomVertexCacheManager *qpGeomVertexCacheManager::_global_ptr = NULL;
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Constructor
-//       Access: Protected
-//  Description: 
-////////////////////////////////////////////////////////////////////
-qpGeomVertexCacheManager::
-qpGeomVertexCacheManager() :
-  _total_size(0)
-{
-  _list = new Entry;
-  _list->_next = _list;
-  _list->_prev = _list;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Destructor
-//       Access: Protected
-//  Description: 
-////////////////////////////////////////////////////////////////////
-qpGeomVertexCacheManager::
-~qpGeomVertexCacheManager() {
-  // Shouldn't be deleting this global object.
-  nassertv(false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::get_global_ptr
-//       Access: Published, Static
-//  Description: Returns the global cache manager pointer.
-////////////////////////////////////////////////////////////////////
-qpGeomVertexCacheManager *qpGeomVertexCacheManager::
-get_global_ptr() {
-  if (_global_ptr == (qpGeomVertexCacheManager *)NULL) {
-    _global_ptr = new qpGeomVertexCacheManager;
-  }
-  return _global_ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::record_data
-//       Access: Private
-//  Description: Records a new generic entry in the cache, or marks a
-//               cache hit for a previous entry in the cache.
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexCacheManager::
-record_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
-  MutexHolder holder(_lock);
-
-  EntriesIndex::iterator ii = _entries_index.find((Entry *)&const_entry);
-  if (ii != _entries_index.end()) {
-    // We already had this entry in the cache.  Refresh it.
-    if (gobj_cat.is_spam()) {
-      gobj_cat.spam()
-        << "refreshing cache entry: " << const_entry << "\n";
-    }
-
-    // Move the previous cache entry to the tail of the list.
-    Entry *entry = (*ii);
-    dequeue_entry(entry);
-    enqueue_entry(entry);
-
-    _total_size += (const_entry._result_size - entry->_result_size);
-    entry->_result_size = const_entry._result_size;
-
-  } else {
-    // There was no such entry already in the cache.  Add it.
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "recording cache entry: " << const_entry << ", total_size = "
-        << _total_size + const_entry._result_size << "\n";
-    }
-    
-    Entry *entry = new Entry(const_entry);
-    enqueue_entry(entry);
-    _total_size += entry->_result_size;
-
-    // Also record an index entry.
-    bool inserted = _entries_index.insert(entry).second;
-    nassertv(inserted);
-  }
-
-  // Now remove any old entries if our cache is over the limit.  This may
-  // also remove the entry we just added, especially if our cache size
-  // is set to 0.
-  int max_size = get_max_size();
-  while (_total_size > max_size) {
-    Entry *entry = _list->_next;
-    nassertv(entry != _list);
-
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "cache total_size = " << _total_size << ", max_size = "
-        << max_size << ", removing " << *entry << "\n";
-    }
-
-    ii = _entries_index.find(entry);
-    nassertv(ii != _entries_index.end());
-
-    switch (entry->_cache_type) {
-    case CT_primitive:
-      entry->_u._primitive->remove_cache_entry();
-      break;
-
-    case CT_geom:
-      entry->_u._geom._source->remove_cache_entry
-        (entry->_u._geom._modifier);
-      break;
-
-    default:
-      break;
-    }
-    _total_size -= entry->_result_size;
-    _entries_index.erase(ii);
-
-    dequeue_entry(entry);
-    delete entry;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::remove_entry
-//       Access: Private
-//  Description: Removes an entry from the cache, if it is there.
-//               Quietly ignores it if it is not.
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexCacheManager::
-remove_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
-  if (gobj_cat.is_debug()) {
-    gobj_cat.debug()
-      << "remove_entry(" << const_entry << ")\n";
-  }
-  MutexHolder holder(_lock);
-
-  EntriesIndex::iterator ii = _entries_index.find((Entry *)&const_entry);
-  if (ii != _entries_index.end()) {
-    Entry *entry = (*ii);
-    _total_size -= entry->_result_size;
-    _entries_index.erase(ii);
-    dequeue_entry(entry);
-    delete entry;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexCacheManager::Entry::output
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexCacheManager::Entry::
-output(ostream &out) const {
-  out << "[ ";
-  switch (_cache_type) {
-  case CT_none:
-    out << "end-of-list token";
-    break;
-
-  case CT_munger:
-    out << "munger " << (void *)_u._munger << ":" 
-        << _u._munger->get_ref_count();
-    break;
-
-  case CT_primitive:
-    out << "primitive " << (void *)_u._primitive;
-    break;
-
-  case CT_geom:
-    out << "geom " << (void *)_u._geom._source << ", " 
-        << (void *)_u._geom._modifier;
-    break;
-  }
-
-  out << ", result_size = " << _result_size << " ]";  
-}

+ 0 - 167
panda/src/gobj/qpgeomVertexCacheManager.h

@@ -1,167 +0,0 @@
-// Filename: qpgeomVertexCacheManager.h
-// Created by:  drose (11Mar05)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef qpGEOMVERTEXCACHEMANAGER_H
-#define qpGEOMVERTEXCACHEMANAGER_H
-
-#include "pandabase.h"
-#include "qpgeomMunger.h"
-#include "config_gobj.h"
-#include "pointerTo.h"
-#include "pmutex.h"
-#include "indirectLess.h"
-#include "plist.h"
-#include "pmap.h"
-
-class qpGeom;
-class qpGeomPrimitive;
-class qpGeomVertexData;
-class qpGeomVertexFormat;
-
-////////////////////////////////////////////////////////////////////
-//       Class : qpGeomVertexCacheManager
-// Description : This is used to keep track of, and limit the size of,
-//               the cache of munged vertices, which would otherwise
-//               be distributed through all of the GeomVertexData
-//               objects in the system.
-//
-//               The actual data in the cache is not stored here, but
-//               rather it is distributed among the various
-//               GeomVertexData source objects.  This allows the cache
-//               data to propagate through the multiprocess pipeline.
-//
-//               This structure actually caches any of a number of
-//               different types of pointers, and mixes them all up in
-//               the same LRU cache list.  Some of them (such as
-//               GeomMunger) are reference-counted here in the cache;
-//               most are not.
-//
-//               This is part of the experimental Geom rewrite.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA qpGeomVertexCacheManager {
-protected:
-  qpGeomVertexCacheManager();
-  ~qpGeomVertexCacheManager();
-
-public:
-  class Entry;
-
-PUBLISHED:
-  INLINE void set_max_size(int max_size) const;
-  INLINE int get_max_size() const;
-
-  INLINE int get_total_size() const;
-
-  static qpGeomVertexCacheManager *get_global_ptr();
-
-private:
-  INLINE void record_munger(const qpGeomMunger *munger);
-  INLINE void record_primitive(const qpGeomPrimitive *primitive,
-                               int result_size);
-  INLINE void remove_primitive(const qpGeomPrimitive *primitive);
-  INLINE void record_geom(const qpGeom *source,
-                          const qpGeomMunger *modifier,
-                          int result_size);
-  INLINE void remove_geom(const qpGeom *source,
-                          const qpGeomMunger *modifier);
-
-  void record_entry(const Entry &const_entry);
-  void remove_entry(const Entry &const_entry);
-
-  INLINE void dequeue_entry(Entry *entry);
-  INLINE void enqueue_entry(Entry *entry);
-
-private:
-  // This mutex protects all operations on this object.
-  Mutex _lock;
-
-  int _total_size;
-
-  enum CacheType {
-    CT_none,
-    CT_munger,
-    CT_primitive,
-    CT_geom,
-  };
-
-public:
-  // This class is public only so we can declare the global ostream
-  // output operator.  It doesn't need to be visible outside this
-  // class.  It contains a single cache entry, which might actually be
-  // any of a handful of different pointer types.  The enumerated type
-  // declared above, and the union declared below, serve to implement
-  // this C-style polymorphism.
-  class Entry {
-  public:
-    INLINE Entry();
-    INLINE Entry(const qpGeomMunger *munger, int result_size);
-    INLINE Entry(const qpGeomPrimitive *primitive, int result_size);
-    INLINE Entry(const qpGeom *source, const qpGeomMunger *modifier, 
-                 int result_size);
-    INLINE Entry(const Entry &copy);
-    INLINE void operator = (const Entry &copy);
-    INLINE ~Entry();
-    INLINE bool operator < (const Entry &other) const;
-
-    void output(ostream &out) const;
-
-    CacheType _cache_type;
-    int _result_size;
-    union {
-      const qpGeomMunger *_munger;
-      const qpGeomPrimitive *_primitive;
-      struct {
-        const qpGeom *_source;
-        const qpGeomMunger *_modifier;
-      } _geom;
-    } _u;
-
-    Entry *_prev, *_next;
-  };
-
-private:
-  // We maintain a doubly-linked list to keep the cache entries in
-  // least-recently-used order: the items at the head of the list are
-  // ready to be flushed.  We use our own doubly-linked list instead
-  // of an STL list, just so we can avoid a tiny bit of overhead,
-  // especially with managing the pointer to the entry in
-  // _entries_index.
-
-  // The tail and the head of the list are both kept by the _prev and
-  // _next pointers, respectively, within the following object, which
-  // always exists solely to keep a handle to the list.  Keeping a
-  // token of the list this way avoids special cases for an empty
-  // list.
-  Entry *_list;
-
-  // And this indexes into the above list, for fast lookup.
-  typedef pset<Entry *, IndirectLess<Entry> > EntriesIndex;
-  EntriesIndex _entries_index;
-
-  static qpGeomVertexCacheManager *_global_ptr;
-
-  friend class qpGeomMunger;
-  friend class qpGeomPrimitive;
-  friend class qpGeom;
-};
-
-INLINE ostream &operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry);
-
-#include "qpgeomVertexCacheManager.I"
-
-#endif