Browse Source

report redundant dups in analyze()

David Rose 18 years ago
parent
commit
f411404617

+ 27 - 0
panda/src/gobj/geomVertexArrayData.cxx

@@ -158,6 +158,33 @@ GeomVertexArrayData::
   release_all();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::compare_to
+//       Access: Published
+//  Description: Returns 0 if the two arrays are equivalent, even if
+//               they are not the same pointer.
+////////////////////////////////////////////////////////////////////
+int GeomVertexArrayData::
+compare_to(const GeomVertexArrayData &other) const {
+  Thread *current_thread = Thread::get_current_thread();
+
+  CPT(GeomVertexArrayDataHandle) handle = get_handle(current_thread);
+  CPT(GeomVertexArrayDataHandle) other_handle = other.get_handle(current_thread);
+
+  if (handle->get_usage_hint() != other_handle->get_usage_hint()) {
+    return (int)handle->get_usage_hint() - (int)other_handle->get_usage_hint();
+  }
+  if (handle->get_array_format() != other_handle->get_array_format()) {
+    return handle->get_array_format() < other_handle->get_array_format() ? -1 : 1;
+  }
+  if (handle->get_data_size_bytes() != other_handle->get_data_size_bytes()) {
+    return (int)handle->get_data_size_bytes() - (int)other_handle->get_data_size_bytes();
+  }
+  return memcmp(handle->get_read_pointer(true), 
+                other_handle->get_read_pointer(true),
+                handle->get_data_size_bytes());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayData::set_usage_hint
 //       Access: Published

+ 2 - 0
panda/src/gobj/geomVertexArrayData.h

@@ -79,6 +79,8 @@ PUBLISHED:
   virtual ~GeomVertexArrayData();
   ALLOC_DELETED_CHAIN(GeomVertexArrayData);
 
+  int compare_to(const GeomVertexArrayData &other) const;
+
   INLINE const GeomVertexArrayFormat *get_array_format() const;
 
   INLINE UsageHint get_usage_hint() const;

+ 40 - 0
panda/src/gobj/geomVertexData.cxx

@@ -198,6 +198,46 @@ GeomVertexData::
   clear_cache();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::compare_to
+//       Access: Published
+//  Description: Returns 0 if the two objects are equivalent, even if
+//               they are not the same pointer.
+////////////////////////////////////////////////////////////////////
+int GeomVertexData::
+compare_to(const GeomVertexData &other) const {
+  Thread *current_thread = Thread::get_current_thread();
+
+  CDReader cdata(_cycler);
+  CDReader other_cdata(other._cycler);
+
+  if (cdata->_usage_hint != other_cdata->_usage_hint) {
+    return (int)cdata->_usage_hint - (int)other_cdata->_usage_hint;
+  }
+  if (cdata->_format != other_cdata->_format) {
+    return cdata->_format < other_cdata->_format ? -1 : 1;
+  }
+  if (cdata->_transform_table != other_cdata->_transform_table) {
+    return cdata->_transform_table < other_cdata->_transform_table ? -1 : 1;
+  }
+  if (cdata->_transform_blend_table != other_cdata->_transform_blend_table) {
+    return cdata->_transform_blend_table < other_cdata->_transform_blend_table ? -1 : 1;
+  }
+  if (cdata->_slider_table != other_cdata->_slider_table) {
+    return cdata->_slider_table < other_cdata->_slider_table ? -1 : 1;
+  }
+  if (cdata->_arrays.size() != other_cdata->_arrays.size()) {
+    return (int)cdata->_arrays.size() - (int)other_cdata->_arrays.size();
+  }
+  for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
+    if (cdata->_arrays[i] != other_cdata->_arrays[i]) {
+      return cdata->_arrays[i] < other_cdata->_arrays[i] ? -1 : 1;
+    }
+  }
+
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::set_name
 //       Access: Published

+ 2 - 0
panda/src/gobj/geomVertexData.h

@@ -93,6 +93,8 @@ PUBLISHED:
   virtual ~GeomVertexData();
   ALLOC_DELETED_CHAIN(GeomVertexData);
 
+  int compare_to(const GeomVertexData &other) const;
+
   INLINE const string &get_name() const;
   void set_name(const string &name);
 

+ 52 - 2
panda/src/pgraph/sceneGraphAnalyzer.cxx

@@ -66,6 +66,8 @@ clear() {
   _nodes.clear();
   _vdatas.clear();
   _vadatas.clear();
+  _unique_vdatas.clear();
+  _unique_vadatas.clear();
   _textures.clear();
 
   _num_nodes = 0;
@@ -153,6 +155,43 @@ write(ostream &out, int indent_level) const {
     << "vertices occupy " << (_vertex_data_size + 1023) / 1024 
     << "K memory.\n";
 
+  int unreferenced_vertices = 0;
+  VDatas::const_iterator vdi;
+  for (vdi = _vdatas.begin(); vdi != _vdatas.end(); ++vdi) {
+    CPT(GeomVertexData) vdata = (*vdi).first;
+    const VDataTracker &tracker = (*vdi).second;
+    int num_unreferenced = vdata->get_num_rows() - tracker._referenced_vertices.get_num_on_bits();
+    nassertv(num_unreferenced >= 0);
+    unreferenced_vertices += num_unreferenced;
+  }
+  if (unreferenced_vertices != 0) {
+    indent(out, indent_level)
+      << unreferenced_vertices << " vertices are unreferenced by any GeomPrimitives.\n";
+  }
+  if (_unique_vdatas.size() != _vdatas.size()) {
+    indent(out, indent_level)
+      << _vdatas.size() - _unique_vdatas.size()
+      << " GeomVertexDatas are redundantly duplicated\n";
+  }
+  if (_unique_vadatas.size() != _vadatas.size()) {
+    int wasted_bytes = 0;
+
+    UniqueVADatas::const_iterator uvai;
+    for (uvai = _unique_vadatas.begin();
+         uvai != _unique_vadatas.end();
+         ++uvai) {
+      const GeomVertexArrayData *gvad = (*uvai).first;
+      int dup_count = (*uvai).second;
+      if (dup_count > 1) {
+        wasted_bytes += (dup_count - 1) * gvad->get_data_size_bytes();
+      }
+    }
+    indent(out, indent_level)
+      << _vadatas.size() - _unique_vadatas.size()
+      << " GeomVertexArrayDatas are redundant, wasting " 
+      << (wasted_bytes + 512) / 1024 << "K.\n";
+  }
+
   indent(out, indent_level)
     << _num_tris << " triangles:\n";
   indent(out, indent_level + 2)
@@ -303,11 +342,14 @@ collect_statistics(GeomNode *geom_node) {
 void SceneGraphAnalyzer::
 collect_statistics(const Geom *geom) {
   CPT(GeomVertexData) vdata = geom->get_vertex_data();
-  bool inserted = _vdatas.insert(vdata).second;
-  if (inserted) {
+  pair<VDatas::iterator, bool> result = _vdatas.insert(VDatas::value_type(vdata, VDataTracker()));
+  if (result.second) {
     // This is the first time we've encountered this vertex data.
     ++_num_geom_vertex_datas;
 
+    int &dup_count = (*(_unique_vdatas.insert(UniqueVDatas::value_type(vdata, 0)).first)).second;
+    ++dup_count;
+
     int num_rows = vdata->get_num_rows();
     if (vdata->has_column(InternalName::get_vertex())) {
       _num_vertices += num_rows;
@@ -327,12 +369,18 @@ collect_statistics(const Geom *geom) {
       collect_statistics(vdata->get_array(i));
     }
   }
+  VDataTracker &tracker = (*(result.first)).second;
 
   // Now consider the primitives in the Geom.
   int num_primitives = geom->get_num_primitives();
   for (int i = 0; i < num_primitives; ++i) {
     CPT(GeomPrimitive) prim = geom->get_primitive(i);
 
+    int num_vertices = prim->get_num_vertices();
+    for (int vi = 0; vi < num_vertices; ++vi) {
+      tracker._referenced_vertices.set_bit(prim->get_vertex(vi));
+    }
+
     if (prim->is_indexed()) {
       collect_statistics(prim->get_vertices());
       if (prim->is_composite()) {
@@ -418,5 +466,7 @@ collect_statistics(const GeomVertexArrayData *vadata) {
   if (inserted) {
     // This is the first time we've encountered this vertex array.
     _vertex_data_size += vadata->get_data_size_bytes();
+    int &dup_count = (*(_unique_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
+    ++dup_count;
   }
 }

+ 12 - 1
panda/src/pgraph/sceneGraphAnalyzer.h

@@ -24,6 +24,8 @@
 #include "luse.h"
 #include "pmap.h"
 #include "pset.h"
+#include "bitArray.h"
+#include "indirectCompareTo.h"
 
 class PandaNode;
 class GeomNode;
@@ -94,9 +96,16 @@ private:
   void collect_statistics(Texture *texture);
   void collect_statistics(const GeomVertexArrayData *vadata);
 
+  class VDataTracker {
+  public:
+    BitArray _referenced_vertices;
+  };
+
   typedef pmap<PandaNode *, int> Nodes;
-  typedef pset<CPT(GeomVertexData) > VDatas;
+  typedef pmap<CPT(GeomVertexData), VDataTracker> VDatas;
   typedef pset<CPT(GeomVertexArrayData) > VADatas;
+  typedef pmap<const GeomVertexData *, int, IndirectCompareTo<GeomVertexData> > UniqueVDatas;
+  typedef pmap<const GeomVertexArrayData *, int, IndirectCompareTo<GeomVertexArrayData> > UniqueVADatas;
   typedef pmap<Texture *, int> Textures;
 
   LodMode _lod_mode;
@@ -104,6 +113,8 @@ private:
   Nodes _nodes;
   VDatas _vdatas;
   VADatas _vadatas;
+  UniqueVDatas _unique_vdatas;
+  UniqueVADatas _unique_vadatas;
   Textures _textures;
 
 private:

+ 30 - 0
panda/src/putil/copyOnWritePointer.I

@@ -85,6 +85,36 @@ INLINE CopyOnWritePointer::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointer::operator == 
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool CopyOnWritePointer::
+operator == (const CopyOnWritePointer &other) const {
+  return _object == other._object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointer::operator != 
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool CopyOnWritePointer::
+operator != (const CopyOnWritePointer &other) const {
+  return _object != other._object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CopyOnWritePointer::operator < 
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool CopyOnWritePointer::
+operator < (const CopyOnWritePointer &other) const {
+  return _object < other._object;
+}
+
 #ifndef COW_THREADED
 ////////////////////////////////////////////////////////////////////
 //     Function: CopyOnWritePointer::get_read_pointer

+ 4 - 0
panda/src/putil/copyOnWritePointer.h

@@ -53,6 +53,10 @@ public:
   INLINE void operator = (CopyOnWriteObject *object);
   INLINE ~CopyOnWritePointer();
 
+  INLINE bool operator == (const CopyOnWritePointer &other) const;
+  INLINE bool operator != (const CopyOnWritePointer &other) const;
+  INLINE bool operator < (const CopyOnWritePointer &other) const;
+
 #ifdef COW_THREADED
   CPT(CopyOnWriteObject) get_read_pointer() const;
   PT(CopyOnWriteObject) get_write_pointer();