Browse Source

simpler do_issue_clip_plane() and do_issue_light(); more pstats calipers

David Rose 18 years ago
parent
commit
93f85f9ef9

+ 0 - 47
panda/src/display/graphicsStateGuardian.I

@@ -17,29 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::LightInfo::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE GraphicsStateGuardian::LightInfo::
-LightInfo() {
-  _enabled = false;
-  _next_enabled = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::ClipPlaneInfo::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE GraphicsStateGuardian::ClipPlaneInfo::
-ClipPlaneInfo() {
-  _enabled = false;
-  _next_enabled = false;
-}
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::release_all
 //     Function: GraphicsStateGuardian::release_all
 //       Access: Public
 //       Access: Public
@@ -759,30 +736,6 @@ get_inv_cs_transform() const {
   return _inv_cs_transform;
   return _inv_cs_transform;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_light
-//       Access: Protected
-//  Description: Returns the Light object that is bound to the
-//               indicated id, or empty NodePath if no Light is bound.
-////////////////////////////////////////////////////////////////////
-INLINE NodePath GraphicsStateGuardian::
-get_light(int light_id) const {
-  nassertr(light_id >= 0 && light_id < (int)_light_info.size(), NodePath::fail());
-  return _light_info[light_id]._light;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_clip_plane
-//       Access: Protected
-//  Description: Returns the PlaneNode object that is bound to the
-//               indicated id, or NULL if no PlaneNode is bound.
-////////////////////////////////////////////////////////////////////
-INLINE NodePath GraphicsStateGuardian::
-get_clip_plane(int plane_id) const {
-  nassertr(plane_id >= 0 && plane_id < (int)_clip_plane_info.size(), NodePath::fail());
-  return _clip_plane_info[plane_id]._plane;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::set_current_properties
 //     Function: GraphicsStateGuardian::set_current_properties
 //       Access: Protected
 //       Access: Protected

+ 97 - 221
panda/src/display/graphicsStateGuardian.cxx

@@ -74,6 +74,29 @@ PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
 PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
 PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
 
 
 
 
+PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
+PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
+PStatCollector GraphicsStateGuardian::_draw_set_state_antialias_pcollector("Draw:Set State:Antialias");
+PStatCollector GraphicsStateGuardian::_draw_set_state_clip_plane_pcollector("Draw:Set State:Clip plane");
+PStatCollector GraphicsStateGuardian::_draw_set_state_color_pcollector("Draw:Set State:Color");
+PStatCollector GraphicsStateGuardian::_draw_set_state_cull_face_pcollector("Draw:Set State:Cull face");
+PStatCollector GraphicsStateGuardian::_draw_set_state_depth_offset_pcollector("Draw:Set State:Depth offset");
+PStatCollector GraphicsStateGuardian::_draw_set_state_depth_test_pcollector("Draw:Set State:Depth test");
+PStatCollector GraphicsStateGuardian::_draw_set_state_depth_write_pcollector("Draw:Set State:Depth write");
+PStatCollector GraphicsStateGuardian::_draw_set_state_render_mode_pcollector("Draw:Set State:Render mode");
+PStatCollector GraphicsStateGuardian::_draw_set_state_rescale_normal_pcollector("Draw:Set State:Rescale normal");
+PStatCollector GraphicsStateGuardian::_draw_set_state_shade_model_pcollector("Draw:Set State:Shade model");
+PStatCollector GraphicsStateGuardian::_draw_set_state_blending_pcollector("Draw:Set State:Blending");
+PStatCollector GraphicsStateGuardian::_draw_set_state_shader_pcollector("Draw:Set State:Shader");
+PStatCollector GraphicsStateGuardian::_draw_set_state_texture_pcollector("Draw:Set State:Texture");
+PStatCollector GraphicsStateGuardian::_draw_set_state_tex_matrix_pcollector("Draw:Set State:Tex matrix");
+PStatCollector GraphicsStateGuardian::_draw_set_state_tex_gen_pcollector("Draw:Set State:Tex gen");
+PStatCollector GraphicsStateGuardian::_draw_set_state_material_pcollector("Draw:Set State:Material");
+PStatCollector GraphicsStateGuardian::_draw_set_state_light_pcollector("Draw:Set State:Light");
+PStatCollector GraphicsStateGuardian::_draw_set_state_stencil_pcollector("Draw:Set State:Stencil");
+PStatCollector GraphicsStateGuardian::_draw_set_state_fog_pcollector("Draw:Set State:Fog");
+
+
 PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
 PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
 
 
 TypeHandle GraphicsStateGuardian::_type_handle;
 TypeHandle GraphicsStateGuardian::_type_handle;
@@ -315,10 +338,8 @@ reset() {
   _texture_involves_color_scale = false;
   _texture_involves_color_scale = false;
   _vertex_colors_enabled = true;
   _vertex_colors_enabled = true;
   _lighting_enabled = false;
   _lighting_enabled = false;
-  _lighting_enabled_this_frame = false;
-
-  _clip_planes_enabled = false;
-  _clip_planes_enabled_this_frame = false;
+  _num_lights_enabled = 0;
+  _num_clip_planes_enabled = 0;
 
 
   _color_scale_enabled = false;
   _color_scale_enabled = false;
   _current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
   _current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
@@ -1132,37 +1153,17 @@ end_scene() {
   // Undo any lighting we had enabled last scene, to force the lights
   // Undo any lighting we had enabled last scene, to force the lights
   // to be reissued, in case their parameters or positions have
   // to be reissued, in case their parameters or positions have
   // changed between scenes.
   // changed between scenes.
-  if (_lighting_enabled_this_frame) {
-    for (int i = 0; i < (int)_light_info.size(); i++) {
-      if (_light_info[i]._enabled) {
-        enable_light(i, false);
-        _light_info[i]._enabled = false;
-      }
-      _light_info[i]._light = NodePath();
-    }
-
-    // Also force the lighting state to unlit, so that issue_light()
-    // will be guaranteed to be called next frame even if we have the
-    // same set of light pointers we had this frame.
-    //    modify_state(get_unlit_state());
-
-    _lighting_enabled_this_frame = false;
+  int i;
+  for (i = 0; i < _num_lights_enabled; ++i) {
+    enable_light(i, false);
   }
   }
+  _num_lights_enabled = 0;
 
 
   // Ditto for the clipping planes.
   // Ditto for the clipping planes.
-  if (_clip_planes_enabled_this_frame) {
-    for (int i = 0; i < (int)_clip_plane_info.size(); i++) {
-      if (_clip_plane_info[i]._enabled) {
-        enable_clip_plane(i, false);
-        _clip_plane_info[i]._enabled = false;
-      }
-      _clip_plane_info[i]._plane = (PlaneNode *)NULL;
-    }
-
-    //    modify_state(get_unclipped_state());
-
-    _clip_planes_enabled_this_frame = false;
+  for (i = 0; i < _num_clip_planes_enabled; ++i) {
+    enable_clip_plane(i, false);
   }
   }
+  _num_clip_planes_enabled = 0;
 
 
   // Put the state into the 'unknown' state, forcing a reload.
   // Put the state into the 'unknown' state, forcing a reload.
   _state_rs = 0;
   _state_rs = 0;
@@ -1417,114 +1418,49 @@ get_cs_transform() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 do_issue_clip_plane() {
 do_issue_clip_plane() {
-  const ClipPlaneAttrib *attrib = _target._clip_plane;
-  int i;
-  int cur_max_planes = (int)_clip_plane_info.size();
-  for (i = 0; i < cur_max_planes; i++) {
-    _clip_plane_info[i]._next_enabled = false;
-  }
-
-  CPT(ClipPlaneAttrib) new_attrib = attrib->filter_to_max(_max_clip_planes);
-
-  bool any_bound = false;
-
   int num_enabled = 0;
   int num_enabled = 0;
-  int num_on_planes = new_attrib->get_num_on_planes();
-  for (int li = 0; li < num_on_planes; li++) {
-    NodePath plane = new_attrib->get_on_plane(li);
-    nassertv(!plane.is_empty() && plane.node()->is_of_type(PlaneNode::get_class_type()));
-    PlaneNode *plane_node = (PlaneNode *)plane.node();
-    if ((plane_node->get_clip_effect() & PlaneNode::CE_visible) != 0) {
-      num_enabled++;
-
-      // Clipping should be enabled before we apply any planes.
-      enable_clip_planes(true);
-      _clip_planes_enabled = true;
-      _clip_planes_enabled_this_frame = true;
-      
-      // Check to see if this plane has already been bound to an id
-      int cur_plane_id = -1;
-      for (i = 0; i < cur_max_planes; i++) {
-        if (_clip_plane_info[i]._plane == plane) {
-          // Plane has already been bound to an id, we only need to
-          // enable the plane, not reapply it.
-          cur_plane_id = -2;
-          enable_clip_plane(i, true);
-          _clip_plane_info[i]._enabled = true;
-          _clip_plane_info[i]._next_enabled = true;
-          break;
-        }
-      }
-      
-      // See if there are any unbound plane ids
-      if (cur_plane_id == -1) {
-        for (i = 0; i < cur_max_planes; i++) {
-          if (_clip_plane_info[i]._plane.is_empty()) {
-            _clip_plane_info[i]._plane = plane;
-            cur_plane_id = i;
-            break;
-          }
-        }
-      }
-      
-      // If there were no unbound plane ids, see if we can replace
-      // a currently unused but previously bound id
-      if (cur_plane_id == -1) {
-        for (i = 0; i < cur_max_planes; i++) {
-          if (!new_attrib->has_on_plane(_clip_plane_info[i]._plane)) {
-            _clip_plane_info[i]._plane = plane;
-            cur_plane_id = i;
-            break;
-          }
+  int num_on_planes = 0;
+
+  if (_target._clip_plane != (ClipPlaneAttrib *)NULL) {
+    CPT(ClipPlaneAttrib) new_plane = _target._clip_plane->filter_to_max(_max_clip_planes);
+
+    num_on_planes = new_plane->get_num_on_planes();
+    for (int li = 0; li < num_on_planes; li++) {
+      NodePath plane = new_plane->get_on_plane(li);
+      nassertv(!plane.is_empty());
+      PlaneNode *plane_node;
+      DCAST_INTO_V(plane_node, plane.node());
+      if ((plane_node->get_clip_effect() & PlaneNode::CE_visible) != 0) {
+        // Clipping should be enabled before we apply any planes.
+        if (!_clip_planes_enabled) {
+          enable_clip_planes(true);
+          _clip_planes_enabled = true;
         }
         }
-      }
-      
-      // If we *still* don't have a plane id, slot a new one.
-      if (cur_plane_id == -1) {
-        if (_max_clip_planes < 0 || cur_max_planes < _max_clip_planes) {
-          cur_plane_id = cur_max_planes;
-          _clip_plane_info.push_back(ClipPlaneInfo());
-          cur_max_planes++;
-          nassertv(cur_max_planes == (int)_clip_plane_info.size());
-        }
-      }
-      
-      if (cur_plane_id >= 0) {
-        enable_clip_plane(cur_plane_id, true);
-        _clip_plane_info[cur_plane_id]._enabled = true;
-        _clip_plane_info[cur_plane_id]._next_enabled = true;
         
         
-        if (!any_bound) {
+        enable_clip_plane(num_enabled, true);
+        if (num_enabled == 0) {
           begin_bind_clip_planes();
           begin_bind_clip_planes();
-          any_bound = true;
         }
         }
         
         
-        // This is the first time this frame that this plane has been
-        // bound to this particular id.
-        bind_clip_plane(plane, cur_plane_id);
-        
-      } else if (cur_plane_id == -1) {
-        gsg_cat.warning()
-          << "Failed to bind " << plane << " to id.\n";
+        bind_clip_plane(plane, num_enabled);
+        num_enabled++;
       }
       }
     }
     }
   }
   }
 
 
-  // Disable all unused planes
-  for (i = 0; i < cur_max_planes; i++) {
-    if (!_clip_plane_info[i]._next_enabled) {
-      enable_clip_plane(i, false);
-      _clip_plane_info[i]._enabled = false;
-    }
+  int i;
+  for (i = num_enabled; i < _num_clip_planes_enabled; ++i) {
+    enable_clip_plane(i, false);
   }
   }
+  _num_clip_planes_enabled = num_enabled;
 
 
-  // If no planes were enabled, disable clip planes in general.
+  // If no planes were set, disable clipping
   if (num_enabled == 0) {
   if (num_enabled == 0) {
-    enable_clip_planes(false);
-    _clip_planes_enabled = false;
-  }
-
-  if (any_bound) {
+    if (_clip_planes_enabled) {
+      enable_clip_planes(false);
+      _clip_planes_enabled = false;
+    }
+  } else {
     end_bind_clip_planes();
     end_bind_clip_planes();
   }
   }
 }
 }
@@ -1649,29 +1585,32 @@ do_issue_light() {
   // light list
   // light list
   Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
   Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
   int i;
   int i;
-  int cur_max_lights = (int)_light_info.size();
-  for (i = 0; i < cur_max_lights; i++) {
-    _light_info[i]._next_enabled = false;
-  }
-
-  bool any_bound = false;
 
 
   int num_enabled = 0;
   int num_enabled = 0;
+  int num_on_lights = 0;
+
+  if (display_cat.is_debug()) {
+    display_cat.debug()
+      << "do_issue_light: " << _target._light << "\n";
+  }
   if (_target._light != (LightAttrib *)NULL) {
   if (_target._light != (LightAttrib *)NULL) {
     CPT(LightAttrib) new_light = _target._light->filter_to_max(_max_lights);
     CPT(LightAttrib) new_light = _target._light->filter_to_max(_max_lights);
+    if (display_cat.is_debug()) {
+      new_light->write(display_cat.debug(false), 2);
+    }
 
 
-    int num_on_lights = new_light->get_num_on_lights();
+    num_on_lights = new_light->get_num_on_lights();
     for (int li = 0; li < num_on_lights; li++) {
     for (int li = 0; li < num_on_lights; li++) {
       NodePath light = new_light->get_on_light(li);
       NodePath light = new_light->get_on_light(li);
-      nassertv(!light.is_empty() && light.node()->as_light() != (Light *)NULL);
+      nassertv(!light.is_empty());
       Light *light_obj = light.node()->as_light();
       Light *light_obj = light.node()->as_light();
-
-      num_enabled++;
+      nassertv(light_obj != (Light *)NULL);
 
 
       // Lighting should be enabled before we apply any lights.
       // Lighting should be enabled before we apply any lights.
-      enable_lighting(true);
-      _lighting_enabled = true;
-      _lighting_enabled_this_frame = true;
+      if (!_lighting_enabled) {
+        enable_lighting(true);
+        _lighting_enabled = true;
+      }
 
 
       if (light_obj->get_type() == AmbientLight::get_class_type()) {
       if (light_obj->get_type() == AmbientLight::get_class_type()) {
         // Ambient lights don't require specific light ids; simply add
         // Ambient lights don't require specific light ids; simply add
@@ -1679,108 +1618,45 @@ do_issue_light() {
         cur_ambient_light += light_obj->get_color();
         cur_ambient_light += light_obj->get_color();
 
 
       } else {
       } else {
-        // Check to see if this light has already been bound to an id
-        int cur_light_id = -1;
-        for (i = 0; i < cur_max_lights; i++) {
-          if (_light_info[i]._light == light) {
-            // Light has already been bound to an id; reuse the same id.
-            cur_light_id = -2;
-            enable_light(i, true);
-            _light_info[i]._enabled = true;
-            _light_info[i]._next_enabled = true;
-
-            if (!any_bound) {
-              begin_bind_lights();
-              any_bound = true;
-            }
-            light_obj->bind(this, light, i);
-            break;
-          }
+        enable_light(num_enabled, true);
+        if (num_enabled == 0) {
+          begin_bind_lights();
         }
         }
 
 
-        // See if there are any unbound light ids
-        if (cur_light_id == -1) {
-          for (i = 0; i < cur_max_lights; i++) {
-            if (_light_info[i]._light.is_empty()) {
-              _light_info[i]._light = light;
-              cur_light_id = i;
-              break;
-            }
-          }
-        }
-
-        // If there were no unbound light ids, see if we can replace
-        // a currently unused but previously bound id
-        if (cur_light_id == -1) {
-          for (i = 0; i < cur_max_lights; i++) {
-            if (!new_light->has_on_light(_light_info[i]._light)) {
-              _light_info[i]._light = light;
-              cur_light_id = i;
-              break;
-            }
-          }
-        }
-
-        // If we *still* don't have a light id, slot a new one.
-        if (cur_light_id == -1) {
-          if (_max_lights < 0 || cur_max_lights < _max_lights) {
-            cur_light_id = cur_max_lights;
-            _light_info.push_back(LightInfo());
-            cur_max_lights++;
-            nassertv(cur_max_lights == (int)_light_info.size());
-          }
-        }
-
-        if (cur_light_id >= 0) {
-          enable_light(cur_light_id, true);
-          _light_info[cur_light_id]._enabled = true;
-          _light_info[cur_light_id]._next_enabled = true;
-
-          if (!any_bound) {
-            begin_bind_lights();
-            any_bound = true;
-          }
-
-          // This is the first time this frame that this light has been
-          // bound to this particular id.
-          light_obj->bind(this, light, cur_light_id);
-
-        } else if (cur_light_id == -1) {
-          gsg_cat.warning()
-            << "Failed to bind " << light << " to id.\n";
-        }
+        light_obj->bind(this, light, num_enabled);
+        num_enabled++;
       }
       }
     }
     }
   }
   }
 
 
-  // Disable all unused lights
-  for (i = 0; i < cur_max_lights; i++) {
-    if (!_light_info[i]._next_enabled) {
-      enable_light(i, false);
-      _light_info[i]._enabled = false;
-    }
+  for (i = num_enabled; i < _num_lights_enabled; ++i) {
+    enable_light(i, false);
   }
   }
+  _num_lights_enabled = num_enabled;
 
 
-  // If no lights were enabled, disable lighting
-  if (num_enabled == 0) {
+  // If no lights were set, disable lighting
+  if (num_on_lights == 0) {
     if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f))) {
     if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f))) {
       // Unless we need lighting anyway to apply a color or color
       // Unless we need lighting anyway to apply a color or color
       // scale.
       // scale.
-      enable_lighting(true);
-      _lighting_enabled = true;
-      _lighting_enabled_this_frame = true;
+      if (!_lighting_enabled) {
+        enable_lighting(true);
+        _lighting_enabled = true;
+      }
       set_ambient_light(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
       set_ambient_light(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
 
 
     } else {
     } else {
-      enable_lighting(false);
-      _lighting_enabled = false;
+      if (_lighting_enabled) {
+        enable_lighting(false);
+        _lighting_enabled = false;
+      }
     }
     }
 
 
   } else {
   } else {
     set_ambient_light(cur_ambient_light);
     set_ambient_light(cur_ambient_light);
   }
   }
 
 
-  if (any_bound) {
+  if (num_enabled != 0) {
     end_bind_lights();
     end_bind_lights();
   }
   }
 }
 }

+ 26 - 23
panda/src/display/graphicsStateGuardian.h

@@ -267,14 +267,12 @@ public:
 #endif
 #endif
 
 
 protected:
 protected:
-  INLINE NodePath get_light(int light_id) const;
   virtual void enable_lighting(bool enable);
   virtual void enable_lighting(bool enable);
   virtual void set_ambient_light(const Colorf &color);
   virtual void set_ambient_light(const Colorf &color);
   virtual void enable_light(int light_id, bool enable);
   virtual void enable_light(int light_id, bool enable);
   virtual void begin_bind_lights();
   virtual void begin_bind_lights();
   virtual void end_bind_lights();
   virtual void end_bind_lights();
 
 
-  INLINE NodePath get_clip_plane(int plane_id) const;
   virtual void enable_clip_planes(bool enable);
   virtual void enable_clip_planes(bool enable);
   virtual void enable_clip_plane(int plane_id, bool enable);
   virtual void enable_clip_plane(int plane_id, bool enable);
   virtual void begin_bind_clip_planes();
   virtual void begin_bind_clip_planes();
@@ -447,28 +445,33 @@ public:
   static PStatCollector _flush_pcollector;
   static PStatCollector _flush_pcollector;
   static PStatCollector _wait_occlusion_pcollector;
   static PStatCollector _wait_occlusion_pcollector;
 
 
-private:
-  class LightInfo {
-  public:
-    INLINE LightInfo();
-    NodePath _light;
-    bool _enabled;
-    bool _next_enabled;
-  };
-
-  pvector<LightInfo> _light_info;
-  bool _lighting_enabled_this_frame;
+  // A whole slew of collectors to measure the cost of individual
+  // state changes.  These are disabled by default.
+  static PStatCollector _draw_set_state_transform_pcollector;
+  static PStatCollector _draw_set_state_alpha_test_pcollector;
+  static PStatCollector _draw_set_state_antialias_pcollector;
+  static PStatCollector _draw_set_state_clip_plane_pcollector;
+  static PStatCollector _draw_set_state_color_pcollector;
+  static PStatCollector _draw_set_state_cull_face_pcollector;
+  static PStatCollector _draw_set_state_depth_offset_pcollector;
+  static PStatCollector _draw_set_state_depth_test_pcollector;
+  static PStatCollector _draw_set_state_depth_write_pcollector;
+  static PStatCollector _draw_set_state_render_mode_pcollector;
+  static PStatCollector _draw_set_state_rescale_normal_pcollector;
+  static PStatCollector _draw_set_state_shade_model_pcollector;
+  static PStatCollector _draw_set_state_blending_pcollector;
+  static PStatCollector _draw_set_state_shader_pcollector;
+  static PStatCollector _draw_set_state_texture_pcollector;
+  static PStatCollector _draw_set_state_tex_matrix_pcollector;
+  static PStatCollector _draw_set_state_tex_gen_pcollector;
+  static PStatCollector _draw_set_state_material_pcollector;
+  static PStatCollector _draw_set_state_light_pcollector;
+  static PStatCollector _draw_set_state_stencil_pcollector;
+  static PStatCollector _draw_set_state_fog_pcollector;
 
 
-  class ClipPlaneInfo {
-  public:
-    INLINE ClipPlaneInfo();
-    NodePath _plane;
-    bool _enabled;
-    bool _next_enabled;
-  };
-
-  pvector<ClipPlaneInfo> _clip_plane_info;
-  bool _clip_planes_enabled_this_frame;
+private:
+  int _num_lights_enabled;
+  int _num_clip_planes_enabled;
 
 
   PT(GraphicsPipe) _pipe;
   PT(GraphicsPipe) _pipe;
   GraphicsEngine *_engine;
   GraphicsEngine *_engine;

+ 68 - 18
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -4036,10 +4036,14 @@ do_issue_blending() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
+  static PStatCollector _draw_set_state_light_bind_point_pcollector("Draw:Set State:Light:Bind:Point");
+  PStatTimer timer(_draw_set_state_light_bind_point_pcollector);
+  
+  float light_color[4];
   GLenum id = get_light_id(light_id);
   GLenum id = get_light_id(light_id);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_color, light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w
   // Position needs to specify x, y, z, and w
@@ -4076,10 +4080,14 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
+  static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
+  PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
+
+  float light_color[4];
   GLenum id = get_light_id( light_id );
   GLenum id = get_light_id( light_id );
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_color, light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w.
   // Position needs to specify x, y, z, and w.
@@ -4117,13 +4125,17 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
+  static PStatCollector _draw_set_state_light_bind_spotlight_pcollector("Draw:Set State:Light:Bind:Spotlight");
+  PStatTimer timer(_draw_set_state_light_bind_spotlight_pcollector);
+  
   Lens *lens = light_obj->get_lens();
   Lens *lens = light_obj->get_lens();
   nassertv(lens != (Lens *)NULL);
   nassertv(lens != (Lens *)NULL);
 
 
+  float light_color[4];
   GLenum id = get_light_id(light_id);
   GLenum id = get_light_id(light_id);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
   GLP(Lightfv)(id, GL_AMBIENT, black.get_data());
-  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_obj));
+  GLP(Lightfv)(id, GL_DIFFUSE, get_light_color(light_color, light_obj));
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
   GLP(Lightfv)(id, GL_SPECULAR, light_obj->get_specular_color().get_data());
 
 
   // Position needs to specify x, y, z, and w
   // Position needs to specify x, y, z, and w
@@ -5564,20 +5576,22 @@ print_gfx_visual() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::get_light_color
 //     Function: GLGraphicsStateGuardian::get_light_color
 //       Access: Public
 //       Access: Public
-//  Description: Returns the array of four floats that should be
-//               issued as the light's color, as scaled by the current
-//               value of _light_color_scale, in the case of
-//               color_scale_via_lighting.
-////////////////////////////////////////////////////////////////////
-const float *CLP(GraphicsStateGuardian)::
-get_light_color(Light *light) const {
-  static Colorf c;
-  c = light->get_color();
-  c.set(c[0] * _light_color_scale[0],
-        c[1] * _light_color_scale[1],
-        c[2] * _light_color_scale[2],
-        c[3] * _light_color_scale[3]);
-  return c.get_data();
+//  Description: Fills the array of four floats with the values that
+//               that should be issued as the light's color, as scaled
+//               by the current value of _light_color_scale, in the
+//               case of color_scale_via_lighting.  Returns
+//               light_color.
+////////////////////////////////////////////////////////////////////
+float *CLP(GraphicsStateGuardian)::
+get_light_color(float light_color[4], Light *light) const {
+  const Colorf &c = light->get_color();
+
+  light_color[0] = c[0] * _light_color_scale[0];
+  light_color[1] = c[1] * _light_color_scale[1];
+  light_color[2] = c[2] * _light_color_scale[2];
+  light_color[3] = c[3] * _light_color_scale[3];
+
+  return light_color;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -5590,6 +5604,9 @@ get_light_color(Light *light) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 enable_lighting(bool enable) {
 enable_lighting(bool enable) {
+  static PStatCollector _draw_set_state_light_enable_lighting_pcollector("Draw:Set State:Light:Enable lighting");
+  PStatTimer timer(_draw_set_state_light_enable_lighting_pcollector);
+  
   if (enable) {
   if (enable) {
     GLP(Enable)(GL_LIGHTING);
     GLP(Enable)(GL_LIGHTING);
   } else {
   } else {
@@ -5607,6 +5624,9 @@ enable_lighting(bool enable) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 set_ambient_light(const Colorf &color) {
 set_ambient_light(const Colorf &color) {
+  static PStatCollector _draw_set_state_light_ambient_pcollector("Draw:Set State:Light:Ambient");
+  PStatTimer timer(_draw_set_state_light_ambient_pcollector);
+  
   Colorf c = color;
   Colorf c = color;
   c.set(c[0] * _light_color_scale[0],
   c.set(c[0] * _light_color_scale[0],
         c[1] * _light_color_scale[1],
         c[1] * _light_color_scale[1],
@@ -5624,6 +5644,9 @@ set_ambient_light(const Colorf &color) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 enable_light(int light_id, bool enable) {
 enable_light(int light_id, bool enable) {
+  static PStatCollector _draw_set_state_light_enable_light_pcollector("Draw:Set State:Light:Enable light");
+  PStatTimer timer(_draw_set_state_light_enable_light_pcollector);
+  
   if (enable) {
   if (enable) {
     GLP(Enable)(get_light_id(light_id));
     GLP(Enable)(get_light_id(light_id));
   } else {
   } else {
@@ -5645,6 +5668,9 @@ enable_light(int light_id, bool enable) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 begin_bind_lights() {
 begin_bind_lights() {
+  static PStatCollector _draw_set_state_light_begin_bind_pcollector("Draw:Set State:Light:Begin bind");
+  PStatTimer timer(_draw_set_state_light_begin_bind_pcollector);
+  
   // We need to temporarily load a new matrix so we can define the
   // We need to temporarily load a new matrix so we can define the
   // light in a known coordinate system.  We pick the transform of the
   // light in a known coordinate system.  We pick the transform of the
   // root.  (Alternatively, we could leave the current transform where
   // root.  (Alternatively, we could leave the current transform where
@@ -5671,6 +5697,9 @@ begin_bind_lights() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 end_bind_lights() {
 end_bind_lights() {
+  static PStatCollector _draw_set_state_light_end_bind_pcollector("Draw:Set State:Light:End bind");
+  PStatTimer timer(_draw_set_state_light_end_bind_pcollector);
+  
   GLP(MatrixMode)(GL_MODELVIEW);
   GLP(MatrixMode)(GL_MODELVIEW);
   GLP(PopMatrix)();
   GLP(PopMatrix)();
 }
 }
@@ -5787,9 +5816,10 @@ set_state_and_transform(const RenderState *target,
 #endif
 #endif
 
 
   _state_pcollector.add_level(1);
   _state_pcollector.add_level(1);
-  PStatTimer timer(_draw_set_state_pcollector);
+  PStatTimer timer1(_draw_set_state_pcollector);
 
 
   if (transform != _internal_transform) {
   if (transform != _internal_transform) {
+    PStatTimer timer(_draw_set_state_transform_pcollector);
     _state_pcollector.add_level(1);
     _state_pcollector.add_level(1);
     _internal_transform = transform;
     _internal_transform = transform;
     do_issue_transform();
     do_issue_transform();
@@ -5804,22 +5834,26 @@ set_state_and_transform(const RenderState *target,
   _state_rs = 0;
   _state_rs = 0;
   
   
   if (_target._alpha_test != _state._alpha_test) {
   if (_target._alpha_test != _state._alpha_test) {
+    PStatTimer timer(_draw_set_state_alpha_test_pcollector);
     do_issue_alpha_test();
     do_issue_alpha_test();
     _state._alpha_test = _target._alpha_test;
     _state._alpha_test = _target._alpha_test;
   }
   }
 
 
   if (_target._antialias != _state._antialias) {
   if (_target._antialias != _state._antialias) {
+    PStatTimer timer(_draw_set_state_antialias_pcollector);
     do_issue_antialias();
     do_issue_antialias();
     _state._antialias = _target._antialias;
     _state._antialias = _target._antialias;
   }
   }
 
 
   if (_target._clip_plane != _state._clip_plane) {
   if (_target._clip_plane != _state._clip_plane) {
+    PStatTimer timer(_draw_set_state_clip_plane_pcollector);
     do_issue_clip_plane();
     do_issue_clip_plane();
     _state._clip_plane = _target._clip_plane;
     _state._clip_plane = _target._clip_plane;
   }
   }
 
 
   if (_target._color != _state._color ||
   if (_target._color != _state._color ||
       _target._color_scale != _state._color_scale) {
       _target._color_scale != _state._color_scale) {
+    PStatTimer timer(_draw_set_state_color_pcollector);
     do_issue_color();
     do_issue_color();
     do_issue_color_scale();
     do_issue_color_scale();
     _state._color = _target._color;
     _state._color = _target._color;
@@ -5827,36 +5861,43 @@ set_state_and_transform(const RenderState *target,
   }
   }
 
 
   if (_target._cull_face != _state._cull_face) {
   if (_target._cull_face != _state._cull_face) {
+    PStatTimer timer(_draw_set_state_cull_face_pcollector);
     do_issue_cull_face();
     do_issue_cull_face();
     _state._cull_face = _target._cull_face;
     _state._cull_face = _target._cull_face;
   }
   }
 
 
   if (_target._depth_offset != _state._depth_offset) {
   if (_target._depth_offset != _state._depth_offset) {
+    PStatTimer timer(_draw_set_state_depth_offset_pcollector);
     do_issue_depth_offset();
     do_issue_depth_offset();
     _state._depth_offset = _target._depth_offset;
     _state._depth_offset = _target._depth_offset;
   }
   }
 
 
   if (_target._depth_test != _state._depth_test) {
   if (_target._depth_test != _state._depth_test) {
+    PStatTimer timer(_draw_set_state_depth_test_pcollector);
     do_issue_depth_test();
     do_issue_depth_test();
     _state._depth_test = _target._depth_test;
     _state._depth_test = _target._depth_test;
   }
   }
 
 
   if (_target._depth_write != _state._depth_write) {
   if (_target._depth_write != _state._depth_write) {
+    PStatTimer timer(_draw_set_state_depth_write_pcollector);
     do_issue_depth_write();
     do_issue_depth_write();
     _state._depth_write = _target._depth_write;
     _state._depth_write = _target._depth_write;
   }
   }
 
 
   if (_target._render_mode != _state._render_mode) {
   if (_target._render_mode != _state._render_mode) {
+    PStatTimer timer(_draw_set_state_render_mode_pcollector);
     do_issue_render_mode();
     do_issue_render_mode();
     _state._render_mode = _target._render_mode;
     _state._render_mode = _target._render_mode;
   }
   }
   
   
   if (_target._rescale_normal != _state._rescale_normal) {
   if (_target._rescale_normal != _state._rescale_normal) {
+    PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
     do_issue_rescale_normal();
     do_issue_rescale_normal();
     _state._rescale_normal = _target._rescale_normal;
     _state._rescale_normal = _target._rescale_normal;
   }
   }
 
 
   if (_target._shade_model != _state._shade_model) {
   if (_target._shade_model != _state._shade_model) {
+    PStatTimer timer(_draw_set_state_shade_model_pcollector);
     do_issue_shade_model();
     do_issue_shade_model();
     _state._shade_model = _target._shade_model;
     _state._shade_model = _target._shade_model;
   }
   }
@@ -5864,6 +5905,7 @@ set_state_and_transform(const RenderState *target,
   if ((_target._transparency != _state._transparency)||
   if ((_target._transparency != _state._transparency)||
       (_target._color_write != _state._color_write)||
       (_target._color_write != _state._color_write)||
       (_target._color_blend != _state._color_blend)) {
       (_target._color_blend != _state._color_blend)) {
+    PStatTimer timer(_draw_set_state_blending_pcollector);
     do_issue_blending();
     do_issue_blending();
     _state._transparency = _target._transparency;
     _state._transparency = _target._transparency;
     _state._color_write = _target._color_write;
     _state._color_write = _target._color_write;
@@ -5871,12 +5913,14 @@ set_state_and_transform(const RenderState *target,
   }
   }
 
 
   if (_target._shader != _state._shader) {
   if (_target._shader != _state._shader) {
+    PStatTimer timer(_draw_set_state_shader_pcollector);
     do_issue_shader();
     do_issue_shader();
     _state._shader = _target._shader;
     _state._shader = _target._shader;
     _state._texture = 0;
     _state._texture = 0;
   }
   }
 
 
   if (_target._texture != _state._texture) {
   if (_target._texture != _state._texture) {
+    PStatTimer timer(_draw_set_state_texture_pcollector);
     determine_effective_texture();
     determine_effective_texture();
     int prev_active = _num_active_texture_stages;
     int prev_active = _num_active_texture_stages;
     do_issue_texture();
     do_issue_texture();
@@ -5902,32 +5946,38 @@ set_state_and_transform(const RenderState *target,
   }
   }
   
   
   if (_target._tex_matrix != _state._tex_matrix) {
   if (_target._tex_matrix != _state._tex_matrix) {
+    PStatTimer timer(_draw_set_state_tex_matrix_pcollector);
     do_issue_tex_matrix();
     do_issue_tex_matrix();
     _state._tex_matrix = _target._tex_matrix;
     _state._tex_matrix = _target._tex_matrix;
   }
   }
 
 
   if (_effective_tex_gen != _state._tex_gen) {
   if (_effective_tex_gen != _state._tex_gen) {
+    PStatTimer timer(_draw_set_state_tex_gen_pcollector);
     do_issue_tex_gen();
     do_issue_tex_gen();
     _state._tex_gen = _effective_tex_gen;
     _state._tex_gen = _effective_tex_gen;
   }
   }
   
   
   if (_target._material != _state._material) {
   if (_target._material != _state._material) {
+    PStatTimer timer(_draw_set_state_material_pcollector);
     do_issue_material();
     do_issue_material();
     _state._material = _target._material;
     _state._material = _target._material;
   }
   }
 
 
   if (_target._light != _state._light) {
   if (_target._light != _state._light) {
+    PStatTimer timer(_draw_set_state_light_pcollector);
     do_issue_light();
     do_issue_light();
     _state._light = _target._light;
     _state._light = _target._light;
   }
   }
 
 
   if (_target._stencil != _state._stencil) {
   if (_target._stencil != _state._stencil) {
+    PStatTimer timer(_draw_set_state_stencil_pcollector);
     do_issue_stencil();
     do_issue_stencil();
     _state._stencil = _target._stencil;
     _state._stencil = _target._stencil;
   }
   }
      
      
   if (_current_shader_context == 0) {
   if (_current_shader_context == 0) {
     if (_target._fog != _state._fog) {
     if (_target._fog != _state._fog) {
+      PStatTimer timer(_draw_set_state_fog_pcollector);
       do_issue_fog();
       do_issue_fog();
       _state._fog = _target._fog;
       _state._fog = _target._fog;
     }
     }

+ 1 - 5
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -179,11 +179,7 @@ public:
 
 
   void print_gfx_visual();
   void print_gfx_visual();
 
 
-  //For those interested in what the guardian thinks is the current
-  //enabled/disable GL State compared to what GL says it is
-  void dump_state();
-
-  const float *get_light_color(Light *light) const;
+  float *get_light_color(float light_color[4], Light *light) const;
 
 
 #ifdef SUPPORT_IMMEDIATE_MODE
 #ifdef SUPPORT_IMMEDIATE_MODE
   void draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode);
   void draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode);

+ 10 - 2
panda/src/pgraph/nodePath.cxx

@@ -66,6 +66,8 @@
 #include "bamFile.h"
 #include "bamFile.h"
 #include "preparedGraphicsObjects.h"
 #include "preparedGraphicsObjects.h"
 #include "dcast.h"
 #include "dcast.h"
+#include "pStatCollector.h"
+#include "pStatTimer.h"
 
 
 // stack seems to overflow on Intel C++ at 7000.  If we need more than 
 // stack seems to overflow on Intel C++ at 7000.  If we need more than 
 // 7000, need to increase stack size.
 // 7000, need to increase stack size.
@@ -706,6 +708,8 @@ get_transform(Thread *current_thread) const {
 CPT(TransformState) NodePath::
 CPT(TransformState) NodePath::
 get_transform(const NodePath &other, Thread *current_thread) const {
 get_transform(const NodePath &other, Thread *current_thread) const {
   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
+  static PStatCollector _get_transform_pcollector("*:NodePath:get_transform");
+  PStatTimer timer(_get_transform_pcollector);
 
 
   if (other.is_empty()) {
   if (other.is_empty()) {
     return get_net_transform(current_thread);
     return get_net_transform(current_thread);
@@ -713,7 +717,7 @@ get_transform(const NodePath &other, Thread *current_thread) const {
   if (is_empty()) {
   if (is_empty()) {
     return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
     return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
   }
   }
-    
+
   nassertr(verify_complete(current_thread), TransformState::make_identity());
   nassertr(verify_complete(current_thread), TransformState::make_identity());
   nassertr(other.verify_complete(current_thread), TransformState::make_identity());
   nassertr(other.verify_complete(current_thread), TransformState::make_identity());
 
 
@@ -744,6 +748,7 @@ get_transform(const NodePath &other, Thread *current_thread) const {
     a_transform = r_get_net_transform(_head, current_thread);
     a_transform = r_get_net_transform(_head, current_thread);
     b_transform = r_get_net_transform(other._head, current_thread);
     b_transform = r_get_net_transform(other._head, current_thread);
   }
   }
+
   return b_transform->invert_compose(a_transform);
   return b_transform->invert_compose(a_transform);
 }
 }
 
 
@@ -5523,7 +5528,7 @@ verify_complete(Thread *current_thread) const {
   }
   }
 
 
 #ifdef HAVE_THREADS
 #ifdef HAVE_THREADS
-  if (Thread::is_threading_supported()) {
+  if (Thread::is_true_threads()) {
     // In a threaded environment, we can't reliably test this, since a
     // In a threaded environment, we can't reliably test this, since a
     // sub-thread may be mucking with the NodePath's ancestry as we
     // sub-thread may be mucking with the NodePath's ancestry as we
     // try to validate it.  NodePaths are inherently not thread-safe,
     // try to validate it.  NodePaths are inherently not thread-safe,
@@ -5532,6 +5537,9 @@ verify_complete(Thread *current_thread) const {
   }
   }
 #endif  // HAVE_THREADS
 #endif  // HAVE_THREADS
 
 
+  static PStatCollector _verify_complete_pcollector("*:NodePath:verify_complete");
+  PStatTimer timer(_verify_complete_pcollector);
+
   const NodePathComponent *comp = _head;
   const NodePathComponent *comp = _head;
   nassertr(comp != (const NodePathComponent *)NULL, false);
   nassertr(comp != (const NodePathComponent *)NULL, false);
 
 

+ 3 - 26
panda/src/pgraph/renderEffects.cxx

@@ -193,32 +193,9 @@ bool RenderEffects::
 operator < (const RenderEffects &other) const {
 operator < (const RenderEffects &other) const {
   // We must compare all the properties of the effects, not just
   // We must compare all the properties of the effects, not just
   // the type; thus, we compare them one at a time using compare_to().
   // the type; thus, we compare them one at a time using compare_to().
-
-  // We could use STL's lexicographical_compare() function here, but
-  // it seems to generate aberrant behavior on OSX and Linux.  We
-  // suspect a compiler bug in gcc.  Instead, we implement the
-  // comparison by hand.
-  Effects::const_iterator ai = _effects.begin();
-  Effects::const_iterator bi = other._effects.begin();
-  while (ai != _effects.end() && bi != other._effects.end()) {
-    int compare = (*ai).compare_to(*bi);
-    if (compare != 0) {
-      return compare < 0;
-    }
-    ++ai;
-    ++bi;
-  }
-  if (ai != _effects.end()) {
-    // bi ran out first..
-    return false;
-  }
-  if (bi != other._effects.end()) {
-    // ai ran out first.
-    return true;
-  }
-
-  // Lists are equivalent.
-  return false;
+  return lexicographical_compare(_effects.begin(), _effects.end(),
+                                 other._effects.begin(), other._effects.end(),
+                                 CompareTo<Effect>());
 }
 }
 
 
 
 

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

@@ -142,6 +142,7 @@ static TimeCollectorProperties time_properties[] = {
   { 1, "*:Animation",                      { 1.0, 0.0, 1.0 } },
   { 1, "*:Animation",                      { 1.0, 0.0, 1.0 } },
   { 0, "*:Flatten",                        { 0.0, 0.7, 0.4 } },
   { 0, "*:Flatten",                        { 0.0, 0.7, 0.4 } },
   { 0, "*:State Cache",                    { 0.4, 0.7, 0.7 } },
   { 0, "*:State Cache",                    { 0.4, 0.7, 0.7 } },
+  { 0, "*:NodePath",                       { 0.1, 0.6, 0.8 } },
   { 1, "Draw",                             { 0.83, 0.02, 0.01 },  1.0 / 30.0 },
   { 1, "Draw",                             { 0.83, 0.02, 0.01 },  1.0 / 30.0 },
   { 1, "Draw:Make current",                { 0.4, 0.2, 0.6 } },
   { 1, "Draw:Make current",                { 0.4, 0.2, 0.6 } },
   { 1, "Draw:Copy texture",                { 0.2, 0.6, 0.4 } },
   { 1, "Draw:Copy texture",                { 0.2, 0.6, 0.4 } },