Browse Source

pstats TransformState, RenderState

David Rose 23 years ago
parent
commit
b2c9c49805

+ 4 - 3
panda/src/display/config_display.cxx

@@ -68,9 +68,10 @@ const bool cull_sorting = config_display.GetBool("cull-sorting", true);
 // (primarily useful for debugging).
 const bool view_frustum_cull = config_display.GetBool("view-frustum-cull", true);
 
-const float gsg_clear_r = config_display.GetFloat("gsg-clear-r", 0.0);
-const float gsg_clear_g = config_display.GetFloat("gsg-clear-g", 0.0);
-const float gsg_clear_b = config_display.GetFloat("gsg-clear-b", 0.0);
+// Set this true to show the number of unused states in the pstats
+// graph for TransformState and RenderState counts.  This adds a bit
+// of per-frame overhead to count these things up.
+const bool pstats_unused_states = config_display.GetBool("pstats-unused-states", false);
 
 
 Config::ConfigTable::Symbol::iterator pipe_modules_begin(void) {

+ 1 - 4
panda/src/display/config_display.h

@@ -38,10 +38,7 @@ extern const bool pipe_spec_is_remote;
 extern const bool compare_state_by_pointer;
 extern const bool cull_sorting;
 extern const bool view_frustum_cull;
-
-extern const float gsg_clear_r;
-extern const float gsg_clear_g;
-extern const float gsg_clear_b;
+extern const bool pstats_unused_states;
 
 extern Config::ConfigTable::Symbol::iterator pipe_modules_begin(void);
 extern Config::ConfigTable::Symbol::iterator pipe_modules_end(void);

+ 40 - 27
panda/src/display/graphicsStateGuardian.cxx

@@ -66,6 +66,10 @@ PStatCollector GraphicsStateGuardian::_frustum_cull_transforms_pcollector("Cull
 
 PStatCollector GraphicsStateGuardian::_set_state_pcollector("Draw:Set state");
 PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive");
+PStatCollector GraphicsStateGuardian::_transform_states_pcollector("TransformStates");
+PStatCollector GraphicsStateGuardian::_transform_states_unused_pcollector("TransformStates:Unused");
+PStatCollector GraphicsStateGuardian::_render_states_pcollector("RenderStates");
+PStatCollector GraphicsStateGuardian::_render_states_unused_pcollector("RenderStates:Unused");
 
 #endif
 
@@ -134,10 +138,10 @@ reset() {
   _transform = TransformState::make_identity();
 
   _buffer_mask = 0;
-  _color_clear_value.set(gsg_clear_r, gsg_clear_g, gsg_clear_b, 0.0);
-  _depth_clear_value = 1.0;
-  _stencil_clear_value = 0.0;
-  _accum_clear_value.set(0.0, 0.0, 0.0, 0.0);
+  _color_clear_value.set(0.0f, 0.0f, 0.0f, 0.0f);
+  _depth_clear_value = 1.0f;
+  _stencil_clear_value = 0.0f;
+  _accum_clear_value.set(0.0f, 0.0f, 0.0f, 0.0f);
   _clear_buffer_type = RenderBuffer::T_back | RenderBuffer::T_depth;
   _normals_enabled = false;
 
@@ -1357,29 +1361,38 @@ close_gsg() {
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 init_frame_pstats() {
-  _current_textures.clear();
-  _current_geoms.clear();
-  _current_geom_nodes.clear();
-  _active_texusage_pcollector.clear_level();
-  _active_geom_pcollector.clear_level();
-  _active_geom_node_pcollector.clear_level();
-
-  // Also clear out our other counters while we're here.
-  _vertices_tristrip_pcollector.clear_level();
-  _vertices_trifan_pcollector.clear_level();
-  _vertices_tri_pcollector.clear_level();
-  _vertices_other_pcollector.clear_level();
-
-  _state_changes_pcollector.clear_level();
-  _transform_state_pcollector.clear_level();
-  _texture_state_pcollector.clear_level();
-
-  _nodes_pcollector.clear_level();
-  _geom_nodes_pcollector.clear_level();
-
-  // Not to mention the view-frustum-cull counters.
-  _frustum_cull_volumes_pcollector.clear_level();
-  _frustum_cull_transforms_pcollector.clear_level();
+  if (PStatClient::is_connected()) {
+    _current_textures.clear();
+    _current_geoms.clear();
+    _current_geom_nodes.clear();
+    _active_texusage_pcollector.clear_level();
+    _active_geom_pcollector.clear_level();
+    _active_geom_node_pcollector.clear_level();
+    
+    // Also clear out our other counters while we're here.
+    _vertices_tristrip_pcollector.clear_level();
+    _vertices_trifan_pcollector.clear_level();
+    _vertices_tri_pcollector.clear_level();
+    _vertices_other_pcollector.clear_level();
+    
+    _state_changes_pcollector.clear_level();
+    _transform_state_pcollector.clear_level();
+    _texture_state_pcollector.clear_level();
+    
+    _nodes_pcollector.clear_level();
+    _geom_nodes_pcollector.clear_level();
+    
+    // Not to mention the view-frustum-cull counters.
+    _frustum_cull_volumes_pcollector.clear_level();
+    _frustum_cull_transforms_pcollector.clear_level();
+    
+    _transform_states_pcollector.set_level(TransformState::get_num_states());
+    _render_states_pcollector.set_level(RenderState::get_num_states());
+    if (pstats_unused_states) {
+      _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
+      _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
panda/src/display/graphicsStateGuardian.h

@@ -284,6 +284,10 @@ public:
   static PStatCollector _frustum_cull_transforms_pcollector;
   static PStatCollector _set_state_pcollector;
   static PStatCollector _draw_primitive_pcollector;
+  static PStatCollector _transform_states_pcollector;
+  static PStatCollector _transform_states_unused_pcollector;
+  static PStatCollector _render_states_pcollector;
+  static PStatCollector _render_states_unused_pcollector;
 
 private:
   class LightInfo {

+ 88 - 2
panda/src/pgraph/renderState.cxx

@@ -622,20 +622,106 @@ get_max_priority() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: RenderState::get_cache_size
+//     Function: RenderState::get_num_states
 //       Access: Published, Static
 //  Description: Returns the total number of unique RenderState
 //               objects allocated in the world.  This will go up and
 //               down during normal operations.
 ////////////////////////////////////////////////////////////////////
 int RenderState::
-get_cache_size() {
+get_num_states() {
   if (_states == (States *)NULL) {
     return 0;
   }
   return _states->size();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_num_unused_states
+//       Access: Published, Static
+//  Description: Returns the total number of RenderState objects that
+//               have been allocated but have no references outside of
+//               the internal RenderState map.
+////////////////////////////////////////////////////////////////////
+int RenderState::
+get_num_unused_states() {
+  if (_states == (States *)NULL) {
+    return 0;
+  }
+
+  int num_unused = 0;
+
+  // First, we need to count the number of times each RenderState
+  // object is recorded in the cache.
+  typedef pmap<const RenderState *, int> StateCount;
+  StateCount state_count;
+
+  States::iterator si;
+  for (si = _states->begin(); si != _states->end(); ++si) {
+    const RenderState *state = (*si);
+
+    CompositionCache::const_iterator ci;
+    for (ci = state->_composition_cache.begin();
+         ci != state->_composition_cache.end();
+         ++ci) {
+      const RenderState *result = (*ci).second._result;
+      if (result != (const RenderState *)NULL) {
+        // Here's a RenderState that's recorded in the cache.
+        // Count it.
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          // If the above insert operation fails, then it's already in
+          // the cache; increment its value.
+          (*(ir.first)).second++;
+        }
+      }
+    }
+    for (ci = state->_invert_composition_cache.begin();
+         ci != state->_invert_composition_cache.end();
+         ++ci) {
+      const RenderState *result = (*ci).second._result;
+      if (result != (const RenderState *)NULL) {
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          (*(ir.first)).second++;
+        }
+      }
+    }
+
+    // Finally, check the self_compose field, which might be reference
+    // counted too.
+    if (state->_self_compose != (const RenderState *)NULL &&
+        state->_self_compose != state) {
+      const RenderState *result = state->_self_compose;
+      if (result != (const RenderState *)NULL) {
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          (*(ir.first)).second++;
+        }
+      }
+    }
+
+  }
+
+  // Now that we have the appearance count of each RenderState
+  // object, we can tell which ones are unreferenced outside of the
+  // RenderState cache, by comparing these to the reference counts.
+  StateCount::iterator sci;
+  for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
+    const RenderState *state = (*sci).first;
+    int count = (*sci).second;
+    nassertr(count <= state->get_ref_count(), num_unused);
+    if (count == state->get_ref_count()) {
+      num_unused++;
+    }
+  }
+
+  return num_unused;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::clear_cache
 //       Access: Published, Static

+ 2 - 1
panda/src/pgraph/renderState.h

@@ -95,7 +95,8 @@ PUBLISHED:
 
   static int get_max_priority();
 
-  static int get_cache_size();
+  static int get_num_states();
+  static int get_num_unused_states();
   static int clear_cache();
 
 public:

+ 88 - 2
panda/src/pgraph/transformState.cxx

@@ -653,20 +653,106 @@ write(ostream &out, int indent_level) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: TransformState::get_cache_size
+//     Function: TransformState::get_num_states
 //       Access: Published, Static
 //  Description: Returns the total number of unique TransformState
 //               objects allocated in the world.  This will go up and
 //               down during normal operations.
 ////////////////////////////////////////////////////////////////////
 int TransformState::
-get_cache_size() {
+get_num_states() {
   if (_states == (States *)NULL) {
     return 0;
   }
   return _states->size();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::get_num_unused_states
+//       Access: Published, Static
+//  Description: Returns the total number of TransformState objects
+//               that have been allocated but have no references
+//               outside of the internal TransformState map.
+////////////////////////////////////////////////////////////////////
+int TransformState::
+get_num_unused_states() {
+  if (_states == (States *)NULL) {
+    return 0;
+  }
+
+  int num_unused = 0;
+
+  // First, we need to count the number of times each TransformState
+  // object is recorded in the cache.
+  typedef pmap<const TransformState *, int> StateCount;
+  StateCount state_count;
+
+  States::iterator si;
+  for (si = _states->begin(); si != _states->end(); ++si) {
+    const TransformState *state = (*si);
+
+    CompositionCache::const_iterator ci;
+    for (ci = state->_composition_cache.begin();
+         ci != state->_composition_cache.end();
+         ++ci) {
+      const TransformState *result = (*ci).second._result;
+      if (result != (const TransformState *)NULL) {
+        // Here's a TransformState that's recorded in the cache.
+        // Count it.
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          // If the above insert operation fails, then it's already in
+          // the cache; increment its value.
+          (*(ir.first)).second++;
+        }
+      }
+    }
+    for (ci = state->_invert_composition_cache.begin();
+         ci != state->_invert_composition_cache.end();
+         ++ci) {
+      const TransformState *result = (*ci).second._result;
+      if (result != (const TransformState *)NULL) {
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          (*(ir.first)).second++;
+        }
+      }
+    }
+
+    // Finally, check the self_compose field, which might be reference
+    // counted too.
+    if (state->_self_compose != (const TransformState *)NULL &&
+        state->_self_compose != state) {
+      const TransformState *result = state->_self_compose;
+      if (result != (const TransformState *)NULL) {
+        pair<StateCount::iterator, bool> ir =
+          state_count.insert(StateCount::value_type(result, 1));
+        if (!ir.second) {
+          (*(ir.first)).second++;
+        }
+      }
+    }
+
+  }
+
+  // Now that we have the appearance count of each TransformState
+  // object, we can tell which ones are unreferenced outside of the
+  // TransformState cache, by comparing these to the reference counts.
+  StateCount::iterator sci;
+  for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
+    const TransformState *state = (*sci).first;
+    int count = (*sci).second;
+    nassertr(count <= state->get_ref_count(), num_unused);
+    if (count == state->get_ref_count()) {
+      num_unused++;
+    }
+  }
+
+  return num_unused;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::clear_cache
 //       Access: Published, Static

+ 2 - 1
panda/src/pgraph/transformState.h

@@ -115,7 +115,8 @@ PUBLISHED:
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
 
-  static int get_cache_size();
+  static int get_num_states();
+  static int get_num_unused_states();
   static int clear_cache();
 
 private:

+ 4 - 0
panda/src/pstatclient/pStatProperties.cxx

@@ -169,6 +169,10 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "Memory usage",                     { 0.5, 1.0, 0.5 },  "MB", 64, 1048576 },
   { 1, "Memory usage:C++",                 { 0.2, 0.2, 1.0 } },
   { 1, "Memory usage:Interpreter",         { 0.8, 0.2, 0.5 } },
+  { 1, "TransformStates",                  { 1.0, 0.5, 0.5 },  "", 5000 },
+  { 1, "TransformStates:Unused",           { 0.2, 0.2, 0.2 } },
+  { 1, "RenderStates",                     { 0.5, 0.5, 1.0 },  "", 1000 },
+  { 1, "RenderStates:Unused",              { 0.2, 0.2, 0.2 } },
   { 0, NULL }
 };