Browse Source

more mutex protection; more current_thread passing

David Rose 19 years ago
parent
commit
fade04905d
42 changed files with 453 additions and 180 deletions
  1. 7 5
      panda/src/chan/movingPartBase.cxx
  2. 3 2
      panda/src/chan/movingPartBase.h
  3. 9 6
      panda/src/chan/partBundle.cxx
  4. 3 2
      panda/src/chan/partGroup.cxx
  5. 3 2
      panda/src/chan/partGroup.h
  6. 9 5
      panda/src/char/characterJoint.cxx
  7. 1 1
      panda/src/char/characterJoint.h
  8. 2 2
      panda/src/char/characterSlider.cxx
  9. 1 1
      panda/src/char/characterSlider.h
  10. 12 2
      panda/src/gobj/geomMunger.cxx
  11. 5 0
      panda/src/gobj/geomMunger.h
  12. 4 2
      panda/src/gobj/geomPrimitive.cxx
  13. 22 18
      panda/src/gobj/geomVertexData.cxx
  14. 4 3
      panda/src/gobj/geomVertexData.h
  15. 4 4
      panda/src/gobj/sliderTable.I
  16. 2 1
      panda/src/gobj/sliderTable.cxx
  17. 2 2
      panda/src/gobj/sliderTable.h
  18. 18 21
      panda/src/gobj/transformBlend.I
  19. 13 9
      panda/src/gobj/transformBlend.cxx
  20. 8 8
      panda/src/gobj/transformBlend.h
  21. 3 3
      panda/src/gobj/transformBlendTable.I
  22. 8 7
      panda/src/gobj/transformBlendTable.cxx
  23. 3 3
      panda/src/gobj/transformBlendTable.h
  24. 4 4
      panda/src/gobj/transformTable.I
  25. 2 1
      panda/src/gobj/transformTable.cxx
  26. 2 2
      panda/src/gobj/transformTable.h
  27. 3 2
      panda/src/gobj/userVertexSlider.I
  28. 3 2
      panda/src/gobj/userVertexTransform.I
  29. 2 2
      panda/src/gobj/vertexSlider.I
  30. 4 4
      panda/src/gobj/vertexSlider.cxx
  31. 2 2
      panda/src/gobj/vertexSlider.h
  32. 4 4
      panda/src/gobj/vertexTransform.I
  33. 6 7
      panda/src/gobj/vertexTransform.cxx
  34. 4 4
      panda/src/gobj/vertexTransform.h
  35. 26 1
      panda/src/pgraph/renderEffects.cxx
  36. 4 0
      panda/src/pgraph/renderEffects.h
  37. 22 0
      panda/src/pgraph/renderState.I
  38. 101 14
      panda/src/pgraph/renderState.cxx
  39. 8 2
      panda/src/pgraph/renderState.h
  40. 40 0
      panda/src/pgraph/transformState.I
  41. 60 17
      panda/src/pgraph/transformState.cxx
  42. 10 3
      panda/src/pgraph/transformState.h

+ 7 - 5
panda/src/chan/movingPartBase.cxx

@@ -99,14 +99,15 @@ write_with_value(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool MovingPartBase::
 bool MovingPartBase::
 do_update(PartBundle *root, PartGroup *parent,
 do_update(PartBundle *root, PartGroup *parent,
-          bool parent_changed, bool anim_changed) {
+          bool parent_changed, bool anim_changed,
+          Thread *current_thread) {
   bool any_changed = false;
   bool any_changed = false;
   bool needs_update = anim_changed;
   bool needs_update = anim_changed;
 
 
   // See if any of the channel values have changed since last time.
   // See if any of the channel values have changed since last time.
 
 
   {
   {
-    PartBundle::CDReader cdata(root->_cycler);
+    PartBundle::CDReader cdata(root->_cycler, current_thread);
     PartBundle::ChannelBlend::const_iterator bci;
     PartBundle::ChannelBlend::const_iterator bci;
     for (bci = cdata->_blend.begin();
     for (bci = cdata->_blend.begin();
          !needs_update && bci != cdata->_blend.end();
          !needs_update && bci != cdata->_blend.end();
@@ -127,14 +128,15 @@ do_update(PartBundle *root, PartGroup *parent,
   }
   }
 
 
   if (parent_changed || needs_update) {
   if (parent_changed || needs_update) {
-    any_changed = update_internals(parent, needs_update, parent_changed);
+    any_changed = update_internals(parent, needs_update, parent_changed,
+                                   current_thread);
   }
   }
 
 
   // Now recurse.
   // Now recurse.
   Children::iterator ci;
   Children::iterator ci;
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
     if ((*ci)->do_update(root, this, parent_changed || needs_update,
     if ((*ci)->do_update(root, this, parent_changed || needs_update,
-                         anim_changed)) {
+                         anim_changed, current_thread)) {
       any_changed = true;
       any_changed = true;
     }
     }
   }
   }
@@ -155,7 +157,7 @@ do_update(PartBundle *root, PartGroup *parent,
 //               result of the update, or false otherwise.
 //               result of the update, or false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool MovingPartBase::
 bool MovingPartBase::
-update_internals(PartGroup *, bool, bool) {
+update_internals(PartGroup *, bool, bool, Thread *) {
   return true;
   return true;
 }
 }
 
 

+ 3 - 2
panda/src/chan/movingPartBase.h

@@ -57,11 +57,12 @@ PUBLISHED:
 
 
 public:
 public:
   virtual bool do_update(PartBundle *root, PartGroup *parent,
   virtual bool do_update(PartBundle *root, PartGroup *parent,
-                         bool parent_changed, bool anim_changed);
+                         bool parent_changed, bool anim_changed,
+                         Thread *current_thread);
 
 
   virtual void get_blend_value(const PartBundle *root)=0;
   virtual void get_blend_value(const PartBundle *root)=0;
   virtual bool update_internals(PartGroup *parent, bool self_changed,
   virtual bool update_internals(PartGroup *parent, bool self_changed,
-                                bool parent_changed);
+                                bool parent_changed, Thread *current_thread);
 
 
 protected:
 protected:
   MovingPartBase();
   MovingPartBase();

+ 9 - 6
panda/src/chan/partBundle.cxx

@@ -240,15 +240,16 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PartBundle::
 bool PartBundle::
 update() {
 update() {
+  Thread *current_thread = Thread::get_current_thread();
   bool anim_changed;
   bool anim_changed;
   {
   {
-    CDReader cdata(_cycler);
+    CDReader cdata(_cycler, current_thread);
     anim_changed = cdata->_anim_changed;
     anim_changed = cdata->_anim_changed;
   }
   }
-  bool any_changed = do_update(this, NULL, false, anim_changed);
+  bool any_changed = do_update(this, NULL, false, anim_changed, current_thread);
 
 
   // Now update all the controls for next time.
   // Now update all the controls for next time.
-  CDWriter cdata(_cycler, false);
+  CDWriter cdata(_cycler, false, current_thread);
   ChannelBlend::const_iterator cbi;
   ChannelBlend::const_iterator cbi;
   for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
   for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
     AnimControl *control = (*cbi).first;
     AnimControl *control = (*cbi).first;
@@ -269,10 +270,11 @@ update() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PartBundle::
 bool PartBundle::
 force_update() {
 force_update() {
-  bool any_changed = do_update(this, NULL, true, true);
+  Thread *current_thread = Thread::get_current_thread();
+  bool any_changed = do_update(this, NULL, true, true, current_thread);
 
 
   // Now update all the controls for next time.
   // Now update all the controls for next time.
-  CDWriter cdata(_cycler, false);
+  CDWriter cdata(_cycler, false, current_thread);
   ChannelBlend::const_iterator cbi;
   ChannelBlend::const_iterator cbi;
   for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
   for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
     AnimControl *control = (*cbi).first;
     AnimControl *control = (*cbi).first;
@@ -428,7 +430,8 @@ clear_and_stop_intersecting(AnimControl *control, CData *cdata) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartBundle::
 void PartBundle::
 finalize(BamReader *) {
 finalize(BamReader *) {
-  do_update(this, NULL, true, true);
+  Thread *current_thread = Thread::get_current_thread();
+  do_update(this, NULL, true, true, current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
panda/src/chan/partGroup.cxx

@@ -361,12 +361,13 @@ write_with_value(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PartGroup::
 bool PartGroup::
 do_update(PartBundle *root, PartGroup *,
 do_update(PartBundle *root, PartGroup *,
-          bool parent_changed, bool anim_changed) {
+          bool parent_changed, bool anim_changed, Thread *current_thread) {
   bool any_changed = false;
   bool any_changed = false;
 
 
   Children::iterator ci;
   Children::iterator ci;
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    if ((*ci)->do_update(root, this, parent_changed, anim_changed)) {
+    if ((*ci)->do_update(root, this, parent_changed, anim_changed,
+                         current_thread)) {
       any_changed = true;
       any_changed = true;
     }
     }
   }
   }

+ 3 - 2
panda/src/chan/partGroup.h

@@ -25,7 +25,7 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "namable.h"
 #include "namable.h"
 #include "typedef.h"
 #include "typedef.h"
-
+#include "thread.h"
 #include "plist.h"
 #include "plist.h"
 
 
 class AnimControl;
 class AnimControl;
@@ -86,7 +86,8 @@ public:
                        int hierarchy_match_flags = 0) const;
                        int hierarchy_match_flags = 0) const;
 
 
   virtual bool do_update(PartBundle *root, PartGroup *parent,
   virtual bool do_update(PartBundle *root, PartGroup *parent,
-                         bool parent_changed, bool anim_changed);
+                         bool parent_changed, bool anim_changed,
+                         Thread *current_thread);
 
 
 protected:
 protected:
   void write_descendants(ostream &out, int indent_level) const;
   void write_descendants(ostream &out, int indent_level) const;

+ 9 - 5
panda/src/char/characterJoint.cxx

@@ -60,9 +60,11 @@ CharacterJoint(PartGroup *parent, const string &name,
                const LMatrix4f &initial_value)
                const LMatrix4f &initial_value)
   : MovingPartMatrix(parent, name, initial_value)
   : MovingPartMatrix(parent, name, initial_value)
 {
 {
+  Thread *current_thread = Thread::get_current_thread();
+
   // Now that we've constructed and we're in the tree, let's call
   // Now that we've constructed and we're in the tree, let's call
   // update_internals() to get our _net_transform set properly.
   // update_internals() to get our _net_transform set properly.
-  update_internals(parent, true, false);
+  update_internals(parent, true, false, current_thread);
 
 
   // And then compute its inverse.  This is needed for
   // And then compute its inverse.  This is needed for
   // ComputedVertices, during animation.
   // ComputedVertices, during animation.
@@ -106,7 +108,9 @@ make_copy() const {
 //               transforms for this particular joint.
 //               transforms for this particular joint.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CharacterJoint::
 bool CharacterJoint::
-update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
+update_internals(PartGroup *parent, bool self_changed, bool parent_changed,
+                 Thread *current_thread) {
+
   nassertr(parent != (PartGroup *)NULL, false);
   nassertr(parent != (PartGroup *)NULL, false);
 
 
   bool net_changed = false;
   bool net_changed = false;
@@ -137,7 +141,7 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
       ai = _net_transform_nodes.begin();
       ai = _net_transform_nodes.begin();
       while (ai != _net_transform_nodes.end()) {
       while (ai != _net_transform_nodes.end()) {
         PandaNode *node = *ai;
         PandaNode *node = *ai;
-        node->set_transform(t);
+        node->set_transform(t, current_thread);
         ++ai;
         ++ai;
       }
       }
     }
     }
@@ -147,7 +151,7 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
     VertexTransforms::iterator vti;
     VertexTransforms::iterator vti;
     for (vti = _vertex_transforms.begin(); vti != _vertex_transforms.end(); ++vti) {
     for (vti = _vertex_transforms.begin(); vti != _vertex_transforms.end(); ++vti) {
       (*vti)->_matrix_stale = true;
       (*vti)->_matrix_stale = true;
-      (*vti)->mark_modified();
+      (*vti)->mark_modified(current_thread);
     }
     }
   }
   }
 
 
@@ -158,7 +162,7 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
     ai = _local_transform_nodes.begin();
     ai = _local_transform_nodes.begin();
     while (ai != _local_transform_nodes.end()) {
     while (ai != _local_transform_nodes.end()) {
       PandaNode *node = *ai;
       PandaNode *node = *ai;
-      node->set_transform(t);
+      node->set_transform(t, current_thread);
       ++ai;
       ++ai;
     }
     }
   }
   }

+ 1 - 1
panda/src/char/characterJoint.h

@@ -44,7 +44,7 @@ public:
   virtual PartGroup *make_copy() const;
   virtual PartGroup *make_copy() const;
 
 
   virtual bool update_internals(PartGroup *parent, bool self_changed,
   virtual bool update_internals(PartGroup *parent, bool self_changed,
-                                bool parent_changed);
+                                bool parent_changed, Thread *current_thread);
 
 
 PUBLISHED:
 PUBLISHED:
   bool add_net_transform(PandaNode *node);
   bool add_net_transform(PandaNode *node);

+ 2 - 2
panda/src/char/characterSlider.cxx

@@ -88,12 +88,12 @@ make_copy() const {
 //               result of the update, or false otherwise.
 //               result of the update, or false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CharacterSlider::
 bool CharacterSlider::
-update_internals(PartGroup *, bool, bool) {
+update_internals(PartGroup *, bool, bool, Thread *current_thread) {
   // Tell our related CharacterVertexSliders that they now need to
   // Tell our related CharacterVertexSliders that they now need to
   // recompute themselves.
   // recompute themselves.
   VertexSliders::iterator vsi;
   VertexSliders::iterator vsi;
   for (vsi = _vertex_sliders.begin(); vsi != _vertex_sliders.end(); ++vsi) {
   for (vsi = _vertex_sliders.begin(); vsi != _vertex_sliders.end(); ++vsi) {
-    (*vsi)->mark_modified();
+    (*vsi)->mark_modified(current_thread);
   }
   }
   
   
   return true;
   return true;

+ 1 - 1
panda/src/char/characterSlider.h

@@ -44,7 +44,7 @@ public:
   virtual PartGroup *make_copy() const;
   virtual PartGroup *make_copy() const;
 
 
   virtual bool update_internals(PartGroup *parent, bool self_changed,
   virtual bool update_internals(PartGroup *parent, bool self_changed,
-                                bool parent_changed);
+                                bool parent_changed, Thread *current_thread);
 
 
 private:
 private:
   typedef pset<CharacterVertexSlider *> VertexSliders;
   typedef pset<CharacterVertexSlider *> VertexSliders;

+ 12 - 2
panda/src/gobj/geomMunger.cxx

@@ -37,7 +37,9 @@ GeomMunger() :
   _is_registered(false)
   _is_registered(false)
 {
 {
 #ifndef NDEBUG
 #ifndef NDEBUG
-  _registered_key = get_registry()->_mungers.end();
+  Registry *registry = get_registry();
+  MutexHolder holder(registry->_registry_lock);
+  _registered_key = registry->_mungers.end();
 #endif
 #endif
 }
 }
 
 
@@ -51,7 +53,9 @@ GeomMunger(const GeomMunger &copy) :
   _is_registered(false)
   _is_registered(false)
 {
 {
 #ifndef NDEBUG
 #ifndef NDEBUG
-  _registered_key = get_registry()->_mungers.end();
+  Registry *registry = get_registry();
+  MutexHolder holder(registry->_registry_lock);
+  _registered_key = registry->_mungers.end();
 #endif
 #endif
 }
 }
 
 
@@ -180,6 +184,8 @@ do_munge_format(const GeomVertexFormat *format,
   nassertr(_is_registered, NULL);
   nassertr(_is_registered, NULL);
   nassertr(format->is_registered(), NULL);
   nassertr(format->is_registered(), NULL);
 
 
+  MutexHolder holder(_formats_lock);
+
   Formats &formats = _formats_by_animation[animation];
   Formats &formats = _formats_by_animation[animation];
 
 
   Formats::iterator fi;
   Formats::iterator fi;
@@ -373,6 +379,8 @@ register_munger(GeomMunger *munger, Thread *current_thread) {
   // will be automatically deleted when this function returns.
   // will be automatically deleted when this function returns.
   PT(GeomMunger) pt_munger = munger;
   PT(GeomMunger) pt_munger = munger;
 
 
+  MutexHolder holder(_registry_lock);
+
   Mungers::iterator mi = _mungers.insert(munger).first;
   Mungers::iterator mi = _mungers.insert(munger).first;
   GeomMunger *new_munger = (*mi);
   GeomMunger *new_munger = (*mi);
   if (!new_munger->is_registered()) {
   if (!new_munger->is_registered()) {
@@ -392,6 +400,8 @@ register_munger(GeomMunger *munger, Thread *current_thread) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomMunger::Registry::
 void GeomMunger::Registry::
 unregister_munger(GeomMunger *munger) {
 unregister_munger(GeomMunger *munger) {
+  MutexHolder holder(_registry_lock);
+
   nassertv(munger->is_registered());
   nassertv(munger->is_registered());
   nassertv(munger->_registered_key != _mungers.end());
   nassertv(munger->_registered_key != _mungers.end());
   _mungers.erase(munger->_registered_key);
   _mungers.erase(munger->_registered_key);

+ 5 - 0
panda/src/gobj/geomMunger.h

@@ -27,6 +27,7 @@
 #include "geomCacheEntry.h"
 #include "geomCacheEntry.h"
 #include "indirectCompareTo.h"
 #include "indirectCompareTo.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"
+#include "pmutex.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "pset.h"
 #include "pset.h"
@@ -111,6 +112,9 @@ private:
   typedef pmap<GeomVertexAnimationSpec, Formats> FormatsByAnimation;
   typedef pmap<GeomVertexAnimationSpec, Formats> FormatsByAnimation;
   FormatsByAnimation _formats_by_animation;
   FormatsByAnimation _formats_by_animation;
 
 
+  // This mutex protects the above.
+  Mutex _formats_lock;
+
   bool _is_registered;
   bool _is_registered;
   typedef pset<GeomMunger *, IndirectCompareTo<GeomMunger> > Mungers;
   typedef pset<GeomMunger *, IndirectCompareTo<GeomMunger> > Mungers;
   class EXPCL_PANDA Registry {
   class EXPCL_PANDA Registry {
@@ -120,6 +124,7 @@ private:
     void unregister_munger(GeomMunger *munger);
     void unregister_munger(GeomMunger *munger);
 
 
     Mungers _mungers;
     Mungers _mungers;
+    Mutex _registry_lock;
   };
   };
 
 
   // We store the iterator into the above registry, while we are
   // We store the iterator into the above registry, while we are

+ 4 - 2
panda/src/gobj/geomPrimitive.cxx

@@ -425,13 +425,14 @@ offset_vertices(int offset) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
+  Thread *current_thread = Thread::get_current_thread();
   int num_vertices = get_num_vertices();
   int num_vertices = get_num_vertices();
   int dest_start = dest->get_num_rows();
   int dest_start = dest->get_num_rows();
 
 
   dest->set_num_rows(dest_start + num_vertices);
   dest->set_num_rows(dest_start + num_vertices);
   for (int i = 0; i < num_vertices; ++i) {
   for (int i = 0; i < num_vertices; ++i) {
     int v = get_vertex(i);
     int v = get_vertex(i);
-    dest->copy_row_from(dest_start + i, source, v);
+    dest->copy_row_from(dest_start + i, source, v, current_thread);
   }
   }
 
 
   set_nonindexed_vertices(dest_start, num_vertices);
   set_nonindexed_vertices(dest_start, num_vertices);
@@ -446,6 +447,7 @@ make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
 pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
+  Thread *current_thread = Thread::get_current_thread();
   if (!is_indexed()) {
   if (!is_indexed()) {
     // If the primitive is nonindexed, packing is the same as
     // If the primitive is nonindexed, packing is the same as
     // converting (again) to nonindexed.
     // converting (again) to nonindexed.
@@ -475,7 +477,7 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
 
 
       if (result.second) {
       if (result.second) {
         // This is the first time we've seen vertex v.
         // This is the first time we've seen vertex v.
-        dest->copy_row_from(v2, source, v);
+        dest->copy_row_from(v2, source, v, current_thread);
       }
       }
     }
     }
     
     

+ 22 - 18
panda/src/gobj/geomVertexData.cxx

@@ -240,9 +240,10 @@ set_usage_hint(GeomVertexData::UsageHint usage_hint) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 set_format(const GeomVertexFormat *format) {
 set_format(const GeomVertexFormat *format) {
+  Thread *current_thread = Thread::get_current_thread();
   nassertv(format->is_registered());
   nassertv(format->is_registered());
 
 
-  CDReader cdata(_cycler);
+  CDReader cdata(_cycler, current_thread);
 
 
   if (format == cdata->_format) {
   if (format == cdata->_format) {
     // Trivially no-op.
     // Trivially no-op.
@@ -269,7 +270,7 @@ set_format(const GeomVertexFormat *format) {
 
 
   // Now copy the original data back in.  This will automatically
   // Now copy the original data back in.  This will automatically
   // convert it to the new format.
   // convert it to the new format.
-  copy_from(orig_data, false);
+  copy_from(orig_data, false, current_thread);
 
 
   clear_cache_stage();
   clear_cache_stage();
   cdataw->_modified = Geom::get_next_modified();
   cdataw->_modified = Geom::get_next_modified();
@@ -289,7 +290,8 @@ set_format(const GeomVertexFormat *format) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 clear_rows() {
 clear_rows() {
-  CDWriter cdata(_cycler, true);
+  Thread *current_thread = Thread::get_current_thread();
+  CDWriter cdata(_cycler, true, current_thread);
   nassertv(cdata->_format->get_num_arrays() == (int)cdata->_arrays.size());
   nassertv(cdata->_format->get_num_arrays() == (int)cdata->_arrays.size());
 
 
   Arrays::iterator ai;
   Arrays::iterator ai;
@@ -321,9 +323,10 @@ clear_rows() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 set_transform_table(const TransformTable *table) {
 set_transform_table(const TransformTable *table) {
+  Thread *current_thread = Thread::get_current_thread();
   nassertv(table == (TransformTable *)NULL || table->is_registered());
   nassertv(table == (TransformTable *)NULL || table->is_registered());
 
 
-  CDWriter cdata(_cycler, true);
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_transform_table = (TransformTable *)table;
   cdata->_transform_table = (TransformTable *)table;
   clear_cache_stage();
   clear_cache_stage();
   cdata->_modified = Geom::get_next_modified();
   cdata->_modified = Geom::get_next_modified();
@@ -428,7 +431,8 @@ set_slider_table(const SliderTable *table) {
 //               have recently made in an upstream thread.
 //               have recently made in an upstream thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
-copy_from(const GeomVertexData *source, bool keep_data_objects) {
+copy_from(const GeomVertexData *source, bool keep_data_objects,
+          Thread *current_thread) {
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *dest_format = get_format();
   const GeomVertexFormat *dest_format = get_format();
 
 
@@ -626,7 +630,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
 copy_row_from(int dest_row, const GeomVertexData *source, 
 copy_row_from(int dest_row, const GeomVertexData *source, 
-              int source_row) {
+              int source_row, Thread *current_thread) {
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *source_format = source->get_format();
   const GeomVertexFormat *dest_format = get_format();
   const GeomVertexFormat *dest_format = get_format();
   nassertv(source_format == dest_format);
   nassertv(source_format == dest_format);
@@ -896,14 +900,14 @@ animate_vertices(Thread *current_thread) const {
   if (cdata->_transform_blend_table != (TransformBlendTable *)NULL) {
   if (cdata->_transform_blend_table != (TransformBlendTable *)NULL) {
     if (cdata->_slider_table != (SliderTable *)NULL) {
     if (cdata->_slider_table != (SliderTable *)NULL) {
       modified = 
       modified = 
-        max(cdata->_transform_blend_table->get_modified(),
-            cdata->_slider_table->get_modified());
+        max(cdata->_transform_blend_table->get_modified(current_thread),
+            cdata->_slider_table->get_modified(current_thread));
     } else {
     } else {
-      modified = cdata->_transform_blend_table->get_modified();
+      modified = cdata->_transform_blend_table->get_modified(current_thread);
     }
     }
 
 
   } else if (cdata->_slider_table != (SliderTable *)NULL) {
   } else if (cdata->_slider_table != (SliderTable *)NULL) {
-    modified = cdata->_slider_table->get_modified();
+    modified = cdata->_slider_table->get_modified(current_thread);
 
 
   } else {
   } else {
     // No transform blend table or slider table--ergo, no vertex
     // No transform blend table or slider table--ergo, no vertex
@@ -918,7 +922,7 @@ animate_vertices(Thread *current_thread) const {
   }
   }
   CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false);
   CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false);
   cdataw->_animated_vertices_modified = modified;
   cdataw->_animated_vertices_modified = modified;
-  ((GeomVertexData *)this)->update_animated_vertices(cdataw);
+  ((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread);
   return cdataw->_animated_vertices;
   return cdataw->_animated_vertices;
 }
 }
 
 
@@ -1186,7 +1190,7 @@ uint8_rgba_to_packed_argb(unsigned char *to, int to_stride,
 //               existing animated_vertices object.
 //               existing animated_vertices object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 void GeomVertexData::
-update_animated_vertices(GeomVertexData::CData *cdata) {
+update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
   int num_rows = get_num_rows();
   int num_rows = get_num_rows();
 
 
   if (gobj_cat.is_debug()) {
   if (gobj_cat.is_debug()) {
@@ -1195,7 +1199,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
       << "\n";
       << "\n";
   }
   }
 
 
-  PStatTimer timer(_char_pcollector);
+  PStatTimer timer(_char_pcollector, current_thread);
 
 
   const GeomVertexFormat *orig_format = cdata->_format;
   const GeomVertexFormat *orig_format = cdata->_format;
 
 
@@ -1203,7 +1207,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
     CPT(GeomVertexFormat) new_format = orig_format->get_post_animated_format();
     CPT(GeomVertexFormat) new_format = orig_format->get_post_animated_format();
     cdata->_animated_vertices = 
     cdata->_animated_vertices = 
       new GeomVertexData(get_name(), new_format,
       new GeomVertexData(get_name(), new_format,
-                           min(get_usage_hint(), UH_dynamic));
+                         min(get_usage_hint(), UH_dynamic));
   }
   }
   PT(GeomVertexData) new_data = cdata->_animated_vertices;
   PT(GeomVertexData) new_data = cdata->_animated_vertices;
 
 
@@ -1275,7 +1279,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
     int num_blends = tb_table->get_num_blends();
     int num_blends = tb_table->get_num_blends();
     int bi;
     int bi;
     for (bi = 0; bi < num_blends; bi++) {
     for (bi = 0; bi < num_blends; bi++) {
-      tb_table->get_blend(bi).update_blend();
+      tb_table->get_blend(bi).update_blend(current_thread);
     }
     }
 
 
     // Now go through and apply the transforms.
     // Now go through and apply the transforms.
@@ -1296,14 +1300,14 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
         for (int i = 0; i < num_rows; i++) {
         for (int i = 0; i < num_rows; i++) {
           LPoint4f vertex = data.get_data4f();
           LPoint4f vertex = data.get_data4f();
           int bi = blendi.get_data1i();
           int bi = blendi.get_data1i();
-          tb_table->get_blend(bi).transform_point(vertex);
+          tb_table->get_blend(bi).transform_point(vertex, current_thread);
           data.set_data4f(vertex);
           data.set_data4f(vertex);
         }
         }
       } else {
       } else {
         for (int i = 0; i < num_rows; i++) {
         for (int i = 0; i < num_rows; i++) {
           LPoint3f vertex = data.get_data3f();
           LPoint3f vertex = data.get_data3f();
           int bi = blendi.get_data1i();
           int bi = blendi.get_data1i();
-          tb_table->get_blend(bi).transform_point(vertex);
+          tb_table->get_blend(bi).transform_point(vertex, current_thread);
           data.set_data3f(vertex);
           data.set_data3f(vertex);
         }
         }
       }
       }
@@ -1315,7 +1319,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
       for (int i = 0; i < num_rows; i++) {
       for (int i = 0; i < num_rows; i++) {
         LVector3f vertex = data.get_data3f();
         LVector3f vertex = data.get_data3f();
         int bi = blendi.get_data1i();
         int bi = blendi.get_data1i();
-        tb_table->get_blend(bi).transform_vector(vertex);
+        tb_table->get_blend(bi).transform_vector(vertex, current_thread);
         data.set_data3f(vertex);
         data.set_data3f(vertex);
       }
       }
     }
     }

+ 4 - 3
panda/src/gobj/geomVertexData.h

@@ -124,9 +124,10 @@ PUBLISHED:
   INLINE int get_num_bytes() const;
   INLINE int get_num_bytes() const;
   INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const;
 
 
-  void copy_from(const GeomVertexData *source, bool keep_data_objects);
+  void copy_from(const GeomVertexData *source, bool keep_data_objects,
+                 Thread *current_thread = Thread::get_current_thread());
   void copy_row_from(int dest_row, const GeomVertexData *source, 
   void copy_row_from(int dest_row, const GeomVertexData *source, 
-                     int source_row);
+                     int source_row, Thread *current_thread);
   CPT(GeomVertexData) convert_to(const GeomVertexFormat *new_format) const;
   CPT(GeomVertexData) convert_to(const GeomVertexFormat *new_format) const;
   CPT(GeomVertexData) 
   CPT(GeomVertexData) 
     scale_color(const LVecBase4f &color_scale) const;
     scale_color(const LVecBase4f &color_scale) const;
@@ -253,7 +254,7 @@ private:
   Cache _cache;
   Cache _cache;
 
 
 private:
 private:
-  void update_animated_vertices(CData *cdata);
+  void update_animated_vertices(CData *cdata, Thread *current_thread);
 
 
   static PStatCollector _convert_pcollector;
   static PStatCollector _convert_pcollector;
   static PStatCollector _scale_color_pcollector;
   static PStatCollector _scale_color_pcollector;

+ 4 - 4
panda/src/gobj/sliderTable.I

@@ -131,8 +131,8 @@ is_empty() const {
 //               changes.)
 //               changes.)
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq SliderTable::
 INLINE UpdateSeq SliderTable::
-get_modified() const {
-  CDReader cdata(_cycler);
+get_modified(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 
@@ -143,8 +143,8 @@ get_modified() const {
 //               reports that it has been modified.
 //               reports that it has been modified.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void SliderTable::
 INLINE void SliderTable::
-update_modified(UpdateSeq modified) {
-  CDWriter cdata(_cycler, true);
+update_modified(UpdateSeq modified, Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_modified = modified;
   cdata->_modified = modified;
 }
 }
 
 

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

@@ -316,5 +316,6 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SliderTable::CData::
 void SliderTable::CData::
 fillin(DatagramIterator &scan, BamReader *manager) {
 fillin(DatagramIterator &scan, BamReader *manager) {
-  _modified = VertexTransform::get_next_modified();
+  Thread *current_thread = Thread::get_current_thread();
+  _modified = VertexTransform::get_next_modified(current_thread);
 }
 }

+ 2 - 2
panda/src/gobj/sliderTable.h

@@ -59,7 +59,7 @@ PUBLISHED:
   INLINE const VertexSlider *find_slider(const InternalName *name) const;
   INLINE const VertexSlider *find_slider(const InternalName *name) const;
   INLINE bool has_slider(const InternalName *name) const;
   INLINE bool has_slider(const InternalName *name) const;
   INLINE bool is_empty() const;
   INLINE bool is_empty() const;
-  INLINE UpdateSeq get_modified() const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   void set_slider(int n, const VertexSlider *slider);
   void set_slider(int n, const VertexSlider *slider);
   void remove_slider(int n);
   void remove_slider(int n);
@@ -70,7 +70,7 @@ PUBLISHED:
 private:
 private:
   void do_register();
   void do_register();
   void do_unregister();
   void do_unregister();
-  INLINE void update_modified(UpdateSeq modified);
+  INLINE void update_modified(UpdateSeq modified, Thread *current_thread);
 
 
 private:
 private:
   bool _is_registered;
   bool _is_registered;

+ 18 - 21
panda/src/gobj/transformBlend.I

@@ -100,7 +100,8 @@ TransformBlend(const TransformBlend &copy) :
 INLINE void TransformBlend::
 INLINE void TransformBlend::
 operator = (const TransformBlend &copy) {
 operator = (const TransformBlend &copy) {
   _entries = copy._entries;
   _entries = copy._entries;
-  clear_result();
+  Thread *current_thread = Thread::get_current_thread();
+  clear_result(current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -209,11 +210,11 @@ set_weight(int n, float weight) {
 //               calling get_blend() or transform_point().
 //               calling get_blend() or transform_point().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformBlend::
 INLINE void TransformBlend::
-update_blend() const {
-  CDReader cdata(_cycler);
-  if (cdata->_global_modified != VertexTransform::get_global_modified()) {
+update_blend(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
+  if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
     CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
     CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
-    ((TransformBlend *)this)->recompute_result(cdataw);
+    ((TransformBlend *)this)->recompute_result(cdataw, current_thread);
   }
   }
 }
 }
 
 
@@ -228,9 +229,8 @@ update_blend() const {
 //               cache is up-to-date before calling this.
 //               cache is up-to-date before calling this.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformBlend::
 INLINE void TransformBlend::
-get_blend(LMatrix4f &result) const {
-  CDReader cdata(_cycler);
-  nassertv(cdata->_global_modified == VertexTransform::get_global_modified());
+get_blend(LMatrix4f &result, Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   result = cdata->_result;
   result = cdata->_result;
 }
 }
 
 
@@ -243,10 +243,9 @@ get_blend(LMatrix4f &result) const {
 //               cache is up-to-date before calling this.
 //               cache is up-to-date before calling this.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformBlend::
 INLINE void TransformBlend::
-transform_point(LPoint4f &point) const {
+transform_point(LPoint4f &point, Thread *current_thread) const {
   if (!_entries.empty()) {
   if (!_entries.empty()) {
-    CDReader cdata(_cycler);
-    nassertv(cdata->_global_modified == VertexTransform::get_global_modified());
+    CDReader cdata(_cycler, current_thread);
     point = point * cdata->_result;
     point = point * cdata->_result;
   }
   }
 }
 }
@@ -260,10 +259,9 @@ transform_point(LPoint4f &point) const {
 //               cache is up-to-date before calling this.
 //               cache is up-to-date before calling this.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformBlend::
 INLINE void TransformBlend::
-transform_point(LPoint3f &point) const {
+transform_point(LPoint3f &point, Thread *current_thread) const {
   if (!_entries.empty()) {
   if (!_entries.empty()) {
-    CDReader cdata(_cycler);
-    nassertv(cdata->_global_modified == VertexTransform::get_global_modified());
+    CDReader cdata(_cycler, current_thread);
     point = point * cdata->_result;
     point = point * cdata->_result;
   }
   }
 }
 }
@@ -277,10 +275,9 @@ transform_point(LPoint3f &point) const {
 //               cache is up-to-date before calling this.
 //               cache is up-to-date before calling this.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformBlend::
 INLINE void TransformBlend::
-transform_vector(LVector3f &vector) const {
+transform_vector(LVector3f &vector, Thread *current_thread) const {
   if (!_entries.empty()) {
   if (!_entries.empty()) {
-    CDReader cdata(_cycler);
-    nassertv(cdata->_global_modified == VertexTransform::get_global_modified());
+    CDReader cdata(_cycler, current_thread);
     vector = vector * cdata->_result;
     vector = vector * cdata->_result;
   }
   }
 }
 }
@@ -292,11 +289,11 @@ transform_vector(LVector3f &vector) const {
 //               least as often as the result of get_blend() changes.
 //               least as often as the result of get_blend() changes.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq TransformBlend::
 INLINE UpdateSeq TransformBlend::
-get_modified() const {
-  CDReader cdata(_cycler);
-  if (cdata->_global_modified != VertexTransform::get_global_modified()) {
+get_modified(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
+  if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
     CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
     CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false);
-    ((TransformBlend *)this)->recompute_result(cdataw);
+    ((TransformBlend *)this)->recompute_result(cdataw, current_thread);
     return cdataw->_modified;
     return cdataw->_modified;
   } else {
   } else {
     return cdata->_modified;
     return cdata->_modified;

+ 13 - 9
panda/src/gobj/transformBlend.cxx

@@ -75,7 +75,8 @@ add_transform(const VertexTransform *transform, float weight) {
         _entries.erase(ei);
         _entries.erase(ei);
       }
       }
     }
     }
-    clear_result();
+    Thread *current_thread = Thread::get_current_thread();
+    clear_result(current_thread);
   }
   }
 }
 }
 
 
@@ -93,7 +94,8 @@ remove_transform(const VertexTransform *transform) {
   if (ei != _entries.end()) {
   if (ei != _entries.end()) {
     _entries.erase(ei);
     _entries.erase(ei);
   }
   }
-  clear_result();
+  Thread *current_thread = Thread::get_current_thread();
+  clear_result(current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -116,7 +118,8 @@ normalize_weights() {
       (*ei)._weight /= net_weight;
       (*ei)._weight /= net_weight;
     }
     }
   }
   }
-  clear_result();
+  Thread *current_thread = Thread::get_current_thread();
+  clear_result(current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -180,6 +183,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlend::
 void TransformBlend::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
+  Thread *current_thread = Thread::get_current_thread();
   Entries::const_iterator ei;
   Entries::const_iterator ei;
   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
     indent(out, indent_level)
     indent(out, indent_level)
@@ -189,7 +193,7 @@ write(ostream &out, int indent_level) const {
     mat.write(out, indent_level + 4);
     mat.write(out, indent_level + 4);
   }
   }
   LMatrix4f blend;
   LMatrix4f blend;
-  get_blend(blend);
+  get_blend(blend, current_thread);
   indent(out, indent_level)
   indent(out, indent_level)
     << "Blended result =\n";
     << "Blended result =\n";
   blend.write(out, indent_level + 2);
   blend.write(out, indent_level + 2);
@@ -202,16 +206,16 @@ write(ostream &out, int indent_level) const {
 //               VertexTransform objects, if necessary.
 //               VertexTransform objects, if necessary.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlend::
 void TransformBlend::
-recompute_result(CData *cdata) {
+recompute_result(CData *cdata, Thread *current_thread) {
   // Update the global_modified sequence number first, to prevent race
   // Update the global_modified sequence number first, to prevent race
   // conditions.
   // conditions.
-  cdata->_global_modified = VertexTransform::get_global_modified();
+  cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
 
 
   // Now see if we really need to recompute.
   // Now see if we really need to recompute.
   UpdateSeq seq;
   UpdateSeq seq;
   Entries::const_iterator ei;
   Entries::const_iterator ei;
   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
-    seq = max(seq, (*ei)._transform->get_modified());
+    seq = max(seq, (*ei)._transform->get_modified(current_thread));
   }
   }
 
 
   if (cdata->_modified != seq) {
   if (cdata->_modified != seq) {
@@ -235,8 +239,8 @@ recompute_result(CData *cdata) {
 //               recomputed.
 //               recomputed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlend::
 void TransformBlend::
-clear_result() {
-  CDWriter cdata(_cycler, true);
+clear_result(Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_global_modified = UpdateSeq();
   cdata->_global_modified = UpdateSeq();
   if (cdata->_modified != UpdateSeq()) {
   if (cdata->_modified != UpdateSeq()) {
     cdata->_modified = UpdateSeq();
     cdata->_modified = UpdateSeq();

+ 8 - 8
panda/src/gobj/transformBlend.h

@@ -70,13 +70,13 @@ PUBLISHED:
   INLINE void set_transform(int n, const VertexTransform *transform);
   INLINE void set_transform(int n, const VertexTransform *transform);
   INLINE void set_weight(int n, float weight);
   INLINE void set_weight(int n, float weight);
 
 
-  INLINE void update_blend() const;
+  INLINE void update_blend(Thread *current_thread) const;
 
 
-  INLINE void get_blend(LMatrix4f &result) const;
-  INLINE void transform_point(LPoint4f &point) const;
-  INLINE void transform_point(LPoint3f &point) const;
-  INLINE void transform_vector(LVector3f &point) const;
-  INLINE UpdateSeq get_modified() const;
+  INLINE void get_blend(LMatrix4f &result, Thread *current_thread) const;
+  INLINE void transform_point(LPoint4f &point, Thread *current_thread) const;
+  INLINE void transform_point(LPoint3f &point, Thread *current_thread) const;
+  INLINE void transform_vector(LVector3f &point, Thread *current_thread) const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
   void write(ostream &out, int indent_level) const;
@@ -84,8 +84,8 @@ PUBLISHED:
 private:
 private:
   class CData;
   class CData;
 
 
-  void recompute_result(CData *cdata);
-  void clear_result();
+  void recompute_result(CData *cdata, Thread *current_thread);
+  void clear_result(Thread *current_thread);
 
 
   class TransformEntry {
   class TransformEntry {
   public:
   public:

+ 3 - 3
panda/src/gobj/transformBlendTable.I

@@ -47,11 +47,11 @@ get_blend(int n) const {
 //               have changed.
 //               have changed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq TransformBlendTable::
 INLINE UpdateSeq TransformBlendTable::
-get_modified() const {
+get_modified(Thread *current_thread) const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
-  if (cdata->_global_modified != VertexTransform::get_global_modified()) {
+  if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) {
     CDWriter cdataw(((TransformBlendTable *)this)->_cycler, cdata, false);
     CDWriter cdataw(((TransformBlendTable *)this)->_cycler, cdata, false);
-    ((TransformBlendTable *)this)->recompute_modified(cdataw);
+    ((TransformBlendTable *)this)->recompute_modified(cdataw, current_thread);
     return cdataw->_modified;
     return cdataw->_modified;
   } else {
   } else {
     return cdata->_modified;
     return cdata->_modified;

+ 8 - 7
panda/src/gobj/transformBlendTable.cxx

@@ -174,16 +174,16 @@ rebuild_index() {
 //               TransformBlend objects, if necessary.
 //               TransformBlend objects, if necessary.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlendTable::
 void TransformBlendTable::
-recompute_modified(TransformBlendTable::CData *cdata) {
+recompute_modified(TransformBlendTable::CData *cdata, Thread *current_thread) {
   // Update the global_modified sequence number first, to prevent race
   // Update the global_modified sequence number first, to prevent race
   // conditions.
   // conditions.
-  cdata->_global_modified = VertexTransform::get_global_modified();
+  cdata->_global_modified = VertexTransform::get_global_modified(current_thread);
 
 
   // Now get the local modified number.
   // Now get the local modified number.
   UpdateSeq seq;
   UpdateSeq seq;
   Blends::const_iterator bi;
   Blends::const_iterator bi;
   for (bi = _blends.begin(); bi != _blends.end(); ++bi) {
   for (bi = _blends.begin(); bi != _blends.end(); ++bi) {
-    seq = max(seq, (*bi).get_modified());
+    seq = max(seq, (*bi).get_modified(current_thread));
   }
   }
 
 
   cdata->_modified = seq;
   cdata->_modified = seq;
@@ -196,8 +196,8 @@ recompute_modified(TransformBlendTable::CData *cdata) {
 //               recomputed.
 //               recomputed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlendTable::
 void TransformBlendTable::
-clear_modified() {
-  CDWriter cdata(_cycler, true);
+clear_modified(Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_global_modified = UpdateSeq();
   cdata->_global_modified = UpdateSeq();
   cdata->_modified = UpdateSeq();
   cdata->_modified = UpdateSeq();
 }
 }
@@ -323,6 +323,7 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformBlendTable::CData::
 void TransformBlendTable::CData::
 fillin(DatagramIterator &scan, BamReader *manager) {
 fillin(DatagramIterator &scan, BamReader *manager) {
-  _modified = VertexTransform::get_next_modified();
-  _global_modified = VertexTransform::get_global_modified();
+  Thread *current_thread = Thread::get_current_thread();
+  _modified = VertexTransform::get_next_modified(current_thread);
+  _global_modified = VertexTransform::get_global_modified(current_thread);
 }
 }

+ 3 - 3
panda/src/gobj/transformBlendTable.h

@@ -58,7 +58,7 @@ PUBLISHED:
 
 
   INLINE int get_num_blends() const;
   INLINE int get_num_blends() const;
   INLINE const TransformBlend &get_blend(int n) const;
   INLINE const TransformBlend &get_blend(int n) const;
-  INLINE UpdateSeq get_modified() const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   void set_blend(int n, const TransformBlend &blend);
   void set_blend(int n, const TransformBlend &blend);
   void remove_blend(int n);
   void remove_blend(int n);
@@ -76,8 +76,8 @@ private:
   INLINE void consider_rebuild_index() const;
   INLINE void consider_rebuild_index() const;
   void rebuild_index();
   void rebuild_index();
 
 
-  void recompute_modified(CData *cdata);
-  void clear_modified();
+  void recompute_modified(CData *cdata, Thread *current_thread);
+  void clear_modified(Thread *current_thread);
 
 
 private:
 private:
   // We don't bother with registering the table, or protecting its
   // We don't bother with registering the table, or protecting its

+ 4 - 4
panda/src/gobj/transformTable.I

@@ -93,8 +93,8 @@ get_transform(int n) const {
 //               changes.)
 //               changes.)
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq TransformTable::
 INLINE UpdateSeq TransformTable::
-get_modified() const {
-  CDReader cdata(_cycler);
+get_modified(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 
@@ -105,8 +105,8 @@ get_modified() const {
 //               reports that it has been modified.
 //               reports that it has been modified.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformTable::
 INLINE void TransformTable::
-update_modified(UpdateSeq modified) {
-  CDWriter cdata(_cycler, true);
+update_modified(UpdateSeq modified, Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_modified = modified;
   cdata->_modified = modified;
 }
 }
 
 

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

@@ -282,5 +282,6 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformTable::CData::
 void TransformTable::CData::
 fillin(DatagramIterator &scan, BamReader *manager) {
 fillin(DatagramIterator &scan, BamReader *manager) {
-  _modified = VertexTransform::get_next_modified();
+  Thread *current_thread = Thread::get_current_thread();
+  _modified = VertexTransform::get_next_modified(current_thread);
 }
 }

+ 2 - 2
panda/src/gobj/transformTable.h

@@ -55,7 +55,7 @@ PUBLISHED:
 
 
   INLINE int get_num_transforms() const;
   INLINE int get_num_transforms() const;
   INLINE const VertexTransform *get_transform(int n) const;
   INLINE const VertexTransform *get_transform(int n) const;
-  INLINE UpdateSeq get_modified() const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   void set_transform(int n, const VertexTransform *transform);
   void set_transform(int n, const VertexTransform *transform);
   void remove_transform(int n);
   void remove_transform(int n);
@@ -66,7 +66,7 @@ PUBLISHED:
 private:
 private:
   void do_register();
   void do_register();
   void do_unregister();
   void do_unregister();
-  INLINE void update_modified(UpdateSeq modified);
+  INLINE void update_modified(UpdateSeq modified, Thread *current_thread);
 
 
 private:
 private:
   bool _is_registered;
   bool _is_registered;

+ 3 - 2
panda/src/gobj/userVertexSlider.I

@@ -24,9 +24,10 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void UserVertexSlider::
 INLINE void UserVertexSlider::
 set_slider(float slider) {
 set_slider(float slider) {
-  CDWriter cdata(_cycler, true);
+  Thread *current_thread = Thread::get_current_thread();
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_slider = slider;
   cdata->_slider = slider;
-  mark_modified();
+  mark_modified(current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
panda/src/gobj/userVertexTransform.I

@@ -35,9 +35,10 @@ get_name() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void UserVertexTransform::
 INLINE void UserVertexTransform::
 set_matrix(const LMatrix4f &matrix) {
 set_matrix(const LMatrix4f &matrix) {
-  CDWriter cdata(_cycler, true);
+  Thread *current_thread = Thread::get_current_thread();
+  CDWriter cdata(_cycler, true, current_thread);
   cdata->_matrix = matrix;
   cdata->_matrix = matrix;
-  mark_modified();
+  mark_modified(current_thread);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/gobj/vertexSlider.I

@@ -38,8 +38,8 @@ get_name() const {
 //               get_slider() changes.
 //               get_slider() changes.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq VertexSlider::
 INLINE UpdateSeq VertexSlider::
-get_modified() const {
-  CDReader cdata(_cycler);
+get_modified(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 

+ 4 - 4
panda/src/gobj/vertexSlider.cxx

@@ -76,13 +76,13 @@ write(ostream &out, int indent_level) const {
 //               be propagated through the system.
 //               be propagated through the system.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void VertexSlider::
 void VertexSlider::
-mark_modified() {
-  CDWriter cdata(_cycler, true);
-  cdata->_modified = VertexTransform::get_next_modified();
+mark_modified(Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
+  cdata->_modified = VertexTransform::get_next_modified(current_thread);
   
   
   Tables::iterator ti;
   Tables::iterator ti;
   for (ti = _tables.begin(); ti != _tables.end(); ++ti) {
   for (ti = _tables.begin(); ti != _tables.end(); ++ti) {
-    (*ti)->update_modified(cdata->_modified);
+    (*ti)->update_modified(cdata->_modified, current_thread);
   }
   }
 }
 }
 
 

+ 2 - 2
panda/src/gobj/vertexSlider.h

@@ -50,13 +50,13 @@ PUBLISHED:
   INLINE const InternalName *get_name() const;
   INLINE const InternalName *get_name() const;
 
 
   virtual float get_slider() const=0;
   virtual float get_slider() const=0;
-  INLINE UpdateSeq get_modified() const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
 protected:
 protected:
-  void mark_modified();
+  void mark_modified(Thread *current_thread);
 
 
 protected:
 protected:
   CPT(InternalName) _name;
   CPT(InternalName) _name;

+ 4 - 4
panda/src/gobj/vertexTransform.I

@@ -25,8 +25,8 @@
 //               get_matrix() changes.
 //               get_matrix() changes.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq VertexTransform::
 INLINE UpdateSeq VertexTransform::
-get_modified() const {
-  CDReader cdata(_cycler);
+get_modified(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 
@@ -39,8 +39,8 @@ get_modified() const {
 //               VertexTransforms have changed value recently.
 //               VertexTransforms have changed value recently.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE UpdateSeq VertexTransform::
 INLINE UpdateSeq VertexTransform::
-get_global_modified() {
-  CDReader cdata(_global_cycler);
+get_global_modified(Thread *current_thread) {
+  CDReader cdata(_global_cycler, current_thread);
   return cdata->_modified;
   return cdata->_modified;
 }
 }
 
 

+ 6 - 7
panda/src/gobj/vertexTransform.cxx

@@ -139,10 +139,9 @@ write(ostream &out, int indent_level) const {
 //               different space.
 //               different space.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 UpdateSeq VertexTransform::
 UpdateSeq VertexTransform::
-get_next_modified() {
+get_next_modified(Thread *current_thread) {
+  CDWriter cdatag(_global_cycler, true, current_thread);
   ++_next_modified;
   ++_next_modified;
-
-  CDWriter cdatag(_global_cycler, true);
   cdatag->_modified = _next_modified;
   cdatag->_modified = _next_modified;
 
 
   return _next_modified;
   return _next_modified;
@@ -157,13 +156,13 @@ get_next_modified() {
 //               be propagated through the system.
 //               be propagated through the system.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void VertexTransform::
 void VertexTransform::
-mark_modified() {
-  CDWriter cdata(_cycler, true);
-  cdata->_modified = get_next_modified();
+mark_modified(Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
+  cdata->_modified = get_next_modified(current_thread);
   
   
   Palettes::iterator pi;
   Palettes::iterator pi;
   for (pi = _tables.begin(); pi != _tables.end(); ++pi) {
   for (pi = _tables.begin(); pi != _tables.end(); ++pi) {
-    (*pi)->update_modified(cdata->_modified);
+    (*pi)->update_modified(cdata->_modified, current_thread);
   }
   }
 }
 }
 
 

+ 4 - 4
panda/src/gobj/vertexTransform.h

@@ -49,16 +49,16 @@ PUBLISHED:
   virtual void mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const;
   virtual void mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const;
   virtual void accumulate_matrix(LMatrix4f &accum, float weight) const;
   virtual void accumulate_matrix(LMatrix4f &accum, float weight) const;
 
 
-  INLINE UpdateSeq get_modified() const;
+  INLINE UpdateSeq get_modified(Thread *current_thread) const;
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
-  static UpdateSeq get_next_modified();
-  INLINE static UpdateSeq get_global_modified();
+  static UpdateSeq get_next_modified(Thread *current_thread);
+  INLINE static UpdateSeq get_global_modified(Thread *current_thread);
 
 
 protected:
 protected:
-  void mark_modified();
+  void mark_modified(Thread *current_thread);
 
 
 private:
 private:
   typedef pset<TransformTable *> Palettes;
   typedef pset<TransformTable *> Palettes;

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

@@ -29,6 +29,7 @@
 #include "indent.h"
 #include "indent.h"
 #include "compareTo.h"
 #include "compareTo.h"
 #include "reMutexHolder.h"
 #include "reMutexHolder.h"
+#include "mutexHolder.h"
 #include "thread.h"
 #include "thread.h"
   
   
 ReMutex *RenderEffects::_states_lock = NULL;
 ReMutex *RenderEffects::_states_lock = NULL;
@@ -44,7 +45,7 @@ TypeHandle RenderEffects::_type_handle;
 //               spurious warning if all constructors are private.
 //               spurious warning if all constructors are private.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderEffects::
 RenderEffects::
-RenderEffects() {
+RenderEffects() : _lock("RenderEffects") {
   if (_states == (States *)NULL) {
   if (_states == (States *)NULL) {
     init_states();
     init_states();
   }
   }
@@ -608,6 +609,12 @@ return_new(RenderEffects *state) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderEffects::
 void RenderEffects::
 determine_decal() {
 determine_decal() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_decal) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderEffect *effect = get_effect(DecalEffect::get_class_type());
   const RenderEffect *effect = get_effect(DecalEffect::get_class_type());
   if (effect != (const RenderEffect *)NULL) {
   if (effect != (const RenderEffect *)NULL) {
     _flags |= F_has_decal;
     _flags |= F_has_decal;
@@ -622,6 +629,12 @@ determine_decal() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderEffects::
 void RenderEffects::
 determine_show_bounds() {
 determine_show_bounds() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_show_bounds) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type());
   const RenderEffect *effect = get_effect(ShowBoundsEffect::get_class_type());
   if (effect != (const RenderEffect *)NULL) {
   if (effect != (const RenderEffect *)NULL) {
     _flags |= F_has_show_bounds;
     _flags |= F_has_show_bounds;
@@ -640,6 +653,12 @@ determine_show_bounds() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderEffects::
 void RenderEffects::
 determine_cull_callback() {
 determine_cull_callback() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_cull_callback) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   _flags |= F_checked_cull_callback;
   _flags |= F_checked_cull_callback;
 
 
   Effects::const_iterator ei;
   Effects::const_iterator ei;
@@ -658,6 +677,12 @@ determine_cull_callback() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderEffects::
 void RenderEffects::
 determine_adjust_transform() {
 determine_adjust_transform() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_adjust_transform) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   _flags |= F_checked_adjust_transform;
   _flags |= F_checked_adjust_transform;
 
 
   Effects::const_iterator ei;
   Effects::const_iterator ei;

+ 4 - 0
panda/src/pgraph/renderEffects.h

@@ -29,6 +29,7 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "ordered_vector.h"
 #include "ordered_vector.h"
 #include "reMutex.h"
 #include "reMutex.h"
+#include "pmutex.h"
 
 
 class CullTraverser;
 class CullTraverser;
 class CullTraverserData;
 class CullTraverserData;
@@ -164,6 +165,9 @@ private:
   };
   };
   int _flags;
   int _flags;
 
 
+  // This mutex protects _flags, and all of the above computed values.
+  Mutex _lock;
+
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 22 - 0
panda/src/pgraph/renderState.I

@@ -389,6 +389,28 @@ get_shader() const {
   return _shader;
   return _shader;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_bin
+//       Access: Private
+//  Description: This is the private implementation of get_bin().
+////////////////////////////////////////////////////////////////////
+INLINE void RenderState::
+determine_bin() {
+  MutexHolder holder(_lock);
+  do_determine_bin();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_transparency
+//       Access: Private
+//  Description: This is the private implementation of get_transparency().
+////////////////////////////////////////////////////////////////////
+INLINE void RenderState::
+determine_transparency() {
+  MutexHolder holder(_lock);
+  do_determine_transparency();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::set_destructing
 //     Function: RenderState::set_destructing
 //       Access: Private
 //       Access: Private

+ 101 - 14
panda/src/pgraph/renderState.cxx

@@ -36,6 +36,7 @@
 #include "indent.h"
 #include "indent.h"
 #include "compareTo.h"
 #include "compareTo.h"
 #include "reMutexHolder.h"
 #include "reMutexHolder.h"
+#include "mutexHolder.h"
 #include "thread.h"
 #include "thread.h"
 #include "attribSlots.h"
 #include "attribSlots.h"
   
   
@@ -61,7 +62,7 @@ TypeHandle RenderState::_type_handle;
 //               spurious warning if all constructors are private.
 //               spurious warning if all constructors are private.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 RenderState::
 RenderState::
-RenderState() {
+RenderState() : _lock("RenderState") {
   if (_states == (States *)NULL) {
   if (_states == (States *)NULL) {
     init_states();
     init_states();
   }
   }
@@ -1444,13 +1445,22 @@ remove_cache_pointers() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_bin_index() {
 determine_bin_index() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_bin_index) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   string bin_name;
   string bin_name;
   _draw_order = 0;
   _draw_order = 0;
 
 
-  const CullBinAttrib *bin_attrib = get_bin();
-  if (bin_attrib != (const CullBinAttrib *)NULL) {
-    bin_name = bin_attrib->get_bin_name();
-    _draw_order = bin_attrib->get_draw_order();
+  if ((_flags & F_checked_bin) == 0) {
+    do_determine_bin();
+  }
+
+  if (_bin != (const CullBinAttrib *)NULL) {
+    bin_name = _bin->get_bin_name();
+    _draw_order = _bin->get_draw_order();
   }
   }
 
 
   if (bin_name.empty()) {
   if (bin_name.empty()) {
@@ -1458,9 +1468,13 @@ determine_bin_index() {
     // either opaque or transparent, based on the transparency
     // either opaque or transparent, based on the transparency
     // setting.
     // setting.
     bin_name = "opaque";
     bin_name = "opaque";
-    const TransparencyAttrib *trans = get_transparency();
-    if (trans != (const TransparencyAttrib *)NULL) {
-      switch (trans->get_mode()) {
+
+    if ((_flags & F_checked_transparency) == 0) {
+      do_determine_transparency();
+    }
+
+    if (_transparency != (const TransparencyAttrib *)NULL) {
+      switch (_transparency->get_mode()) {
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_alpha:
       case TransparencyAttrib::M_dual:
       case TransparencyAttrib::M_dual:
         // These transparency modes require special back-to-front sorting.
         // These transparency modes require special back-to-front sorting.
@@ -1490,6 +1504,12 @@ determine_bin_index() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_fog() {
 determine_fog() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_fog) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(FogAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(FogAttrib::get_class_type());
   _fog = (const FogAttrib *)NULL;
   _fog = (const FogAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1499,12 +1519,18 @@ determine_fog() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: RenderState::determine_bin
+//     Function: RenderState::do_determine_bin
 //       Access: Private
 //       Access: Private
-//  Description: This is the private implementation of get_bin().
+//  Description: This is the implementation of determine_bin(); it
+//               assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
-determine_bin() {
+do_determine_bin() {
+  if ((_flags & F_checked_bin) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type());
   _bin = (const CullBinAttrib *)NULL;
   _bin = (const CullBinAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1514,12 +1540,19 @@ determine_bin() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: RenderState::determine_transparency
+//     Function: RenderState::do_determine_transparency
 //       Access: Private
 //       Access: Private
-//  Description: This is the private implementation of get_transparency().
+//  Description: This is the implementation of
+//               determine_transparency(); it assumes the lock is
+//               already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
-determine_transparency() {
+do_determine_transparency() {
+  if ((_flags & F_checked_transparency) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = 
   const RenderAttrib *attrib = 
     get_attrib(TransparencyAttrib::get_class_type());
     get_attrib(TransparencyAttrib::get_class_type());
   _transparency = (const TransparencyAttrib *)NULL;
   _transparency = (const TransparencyAttrib *)NULL;
@@ -1536,6 +1569,12 @@ determine_transparency() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_color() {
 determine_color() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_color) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(ColorAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(ColorAttrib::get_class_type());
   _color = (const ColorAttrib *)NULL;
   _color = (const ColorAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1551,6 +1590,12 @@ determine_color() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_color_scale() {
 determine_color_scale() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_color_scale) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(ColorScaleAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(ColorScaleAttrib::get_class_type());
   _color_scale = (const ColorScaleAttrib *)NULL;
   _color_scale = (const ColorScaleAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1566,6 +1611,12 @@ determine_color_scale() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_texture() {
 determine_texture() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_texture) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(TextureAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(TextureAttrib::get_class_type());
   _texture = (const TextureAttrib *)NULL;
   _texture = (const TextureAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1581,6 +1632,12 @@ determine_texture() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_tex_gen() {
 determine_tex_gen() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_tex_gen) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(TexGenAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(TexGenAttrib::get_class_type());
   _tex_gen = (const TexGenAttrib *)NULL;
   _tex_gen = (const TexGenAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1596,6 +1653,12 @@ determine_tex_gen() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_tex_matrix() {
 determine_tex_matrix() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_tex_matrix) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(TexMatrixAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(TexMatrixAttrib::get_class_type());
   _tex_matrix = (const TexMatrixAttrib *)NULL;
   _tex_matrix = (const TexMatrixAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1611,6 +1674,12 @@ determine_tex_matrix() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_render_mode() {
 determine_render_mode() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_render_mode) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(RenderModeAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(RenderModeAttrib::get_class_type());
   _render_mode = (const RenderModeAttrib *)NULL;
   _render_mode = (const RenderModeAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1626,6 +1695,12 @@ determine_render_mode() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_clip_plane() {
 determine_clip_plane() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_clip_plane) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(ClipPlaneAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(ClipPlaneAttrib::get_class_type());
   _clip_plane = (const ClipPlaneAttrib *)NULL;
   _clip_plane = (const ClipPlaneAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1641,6 +1716,12 @@ determine_clip_plane() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_shader() {
 determine_shader() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_shader) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   const RenderAttrib *attrib = get_attrib(ShaderAttrib::get_class_type());
   const RenderAttrib *attrib = get_attrib(ShaderAttrib::get_class_type());
   _shader = (const ShaderAttrib *)NULL;
   _shader = (const ShaderAttrib *)NULL;
   if (attrib != (const RenderAttrib *)NULL) {
   if (attrib != (const RenderAttrib *)NULL) {
@@ -1656,6 +1737,12 @@ determine_shader() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void RenderState::
 void RenderState::
 determine_cull_callback() {
 determine_cull_callback() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_checked_cull_callback) != 0) {
+    // Someone else checked it first.
+    return;
+  }
+
   Attributes::const_iterator ai;
   Attributes::const_iterator ai;
   for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) {
   for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) {
     const Attribute &attrib = *ai;
     const Attribute &attrib = *ai;

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

@@ -33,6 +33,7 @@
 #include "weakPointerTo.h"
 #include "weakPointerTo.h"
 #include "shaderExpansion.h"
 #include "shaderExpansion.h"
 #include "reMutex.h"
 #include "reMutex.h"
+#include "pmutex.h"
 #include "deletedChain.h"
 #include "deletedChain.h"
 
 
 class GraphicsStateGuardianBase;
 class GraphicsStateGuardianBase;
@@ -182,8 +183,10 @@ private:
 
 
   void determine_bin_index();
   void determine_bin_index();
   void determine_fog();
   void determine_fog();
-  void determine_bin();
-  void determine_transparency();
+  INLINE void determine_bin();
+  void do_determine_bin();
+  INLINE void determine_transparency();
+  void do_determine_transparency();
   void determine_color();
   void determine_color();
   void determine_color_scale();
   void determine_color_scale();
   void determine_texture();
   void determine_texture();
@@ -324,6 +327,9 @@ private:
   };
   };
   unsigned short _flags;
   unsigned short _flags;
 
 
+  // This mutex protects _flags, and all of the above computed values.
+  Mutex _lock;
+
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 40 - 0
panda/src/pgraph/transformState.I

@@ -824,6 +824,40 @@ check_mat() const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::calc_components
+//       Access: Private
+//  Description: Derives the components from the matrix, if possible.
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+calc_components() {
+  MutexHolder holder(_lock);
+  do_calc_components();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::calc_hpr
+//       Access: Private
+//  Description: Derives the hpr, from the matrix if necessary, or
+//               from the quat.
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+calc_hpr() {
+  MutexHolder holder(_lock);
+  do_calc_hpr();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TransformState::calc_mat
+//       Access: Private
+//  Description: Computes the matrix from the components.
+////////////////////////////////////////////////////////////////////
+INLINE void TransformState::
+calc_mat() {
+  MutexHolder holder(_lock);
+  do_calc_mat();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TransformState::check_uniform_scale
 //     Function: TransformState::check_uniform_scale
 //       Access: Private
 //       Access: Private
@@ -831,6 +865,9 @@ check_mat() const {
 //               F_has_components) is set, this checks for a
 //               F_has_components) is set, this checks for a
 //               identity and/or uniform scale (as well as a non-zero
 //               identity and/or uniform scale (as well as a non-zero
 //               shear) and sets the bit appropriately.
 //               shear) and sets the bit appropriately.
+//
+//               It does not matter whether the lock is or is not held
+//               before calling this method.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformState::
 INLINE void TransformState::
 check_uniform_scale() {
 check_uniform_scale() {
@@ -854,6 +891,9 @@ check_uniform_scale() {
 //               F_has_components) is set, for a known 2-d scale, this
 //               F_has_components) is set, for a known 2-d scale, this
 //               checks for a identity and/or uniform scale (as well
 //               checks for a identity and/or uniform scale (as well
 //               as a non-zero shear) and sets the bit appropriately.
 //               as a non-zero shear) and sets the bit appropriately.
+//
+//               It does not matter whether the lock is or is not held
+//               before calling this method.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TransformState::
 INLINE void TransformState::
 check_uniform_scale2d() {
 check_uniform_scale2d() {

+ 60 - 17
panda/src/pgraph/transformState.cxx

@@ -26,6 +26,7 @@
 #include "pStatTimer.h"
 #include "pStatTimer.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
 #include "reMutexHolder.h"
 #include "reMutexHolder.h"
+#include "mutexHolder.h"
 #include "thread.h"
 #include "thread.h"
 
 
 ReMutex *TransformState::_states_lock = NULL;
 ReMutex *TransformState::_states_lock = NULL;
@@ -48,7 +49,7 @@ TypeHandle TransformState::_type_handle;
 //               spurious warning if all constructors are private.
 //               spurious warning if all constructors are private.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TransformState::
 TransformState::
-TransformState() {
+TransformState() : _lock("TransformState") {
   if (_states == (States *)NULL) {
   if (_states == (States *)NULL) {
     init_states();
     init_states();
   }
   }
@@ -1743,6 +1744,11 @@ remove_cache_pointers() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
 calc_singular() {
 calc_singular() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_singular_known) != 0) {
+    // Someone else computed it first.
+    return;
+  }
   nassertv((_flags & F_is_invalid) == 0);
   nassertv((_flags & F_is_invalid) == 0);
 
 
   // We determine if a matrix is singular by attempting to invert it
   // We determine if a matrix is singular by attempting to invert it
@@ -1753,7 +1759,11 @@ calc_singular() {
   // This should be NULL if no one has called calc_singular() yet.
   // This should be NULL if no one has called calc_singular() yet.
   nassertv(_inv_mat == (LMatrix4f *)NULL);
   nassertv(_inv_mat == (LMatrix4f *)NULL);
   _inv_mat = new LMatrix4f;
   _inv_mat = new LMatrix4f;
-  bool inverted = _inv_mat->invert_from(get_mat());
+
+  if ((_flags & F_mat_known) == 0) {
+    do_calc_mat();
+  }
+  bool inverted = _inv_mat->invert_from(_mat);
 
 
   if (!inverted) {
   if (!inverted) {
     _flags |= F_is_singular;
     _flags |= F_is_singular;
@@ -1764,12 +1774,18 @@ calc_singular() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TransformState::calc_components
+//     Function: TransformState::do_calc_components
 //       Access: Private
 //       Access: Private
-//  Description: Derives the components from the matrix, if possible.
+//  Description: This is the implementation of calc_components(); it
+//               assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
-calc_components() {
+do_calc_components() {
+  if ((_flags & F_components_known) != 0) {
+    // Someone else computed it first.
+    return;
+  }
+
   nassertv((_flags & F_is_invalid) == 0);
   nassertv((_flags & F_is_invalid) == 0);
   if ((_flags & F_is_identity) != 0) {
   if ((_flags & F_is_identity) != 0) {
     _scale.set(1.0f, 1.0f, 1.0f);
     _scale.set(1.0f, 1.0f, 1.0f);
@@ -1784,8 +1800,10 @@ calc_components() {
     // other explanation is that we were constructed via a matrix.
     // other explanation is that we were constructed via a matrix.
     nassertv((_flags & F_mat_known) != 0);
     nassertv((_flags & F_mat_known) != 0);
 
 
-    const LMatrix4f &mat = get_mat();
-    bool possible = decompose_matrix(mat, _scale, _shear, _hpr, _pos);
+    if ((_flags & F_mat_known) == 0) {
+      do_calc_mat();
+    }
+    bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos);
     if (!possible) {
     if (!possible) {
       // Some matrices can't be decomposed into scale, hpr, pos.  In
       // Some matrices can't be decomposed into scale, hpr, pos.  In
       // this case, we now know that we cannot compute the components;
       // this case, we now know that we cannot compute the components;
@@ -1799,20 +1817,27 @@ calc_components() {
     }
     }
 
 
     // However, we can always get at least the pos.
     // However, we can always get at least the pos.
-    mat.get_row3(_pos, 3);
+    _mat.get_row3(_pos, 3);
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TransformState::calc_hpr
+//     Function: TransformState::do_calc_hpr
 //       Access: Private
 //       Access: Private
-//  Description: Derives the hpr, from the matrix if necessary, or
-//               from the quat.
+//  Description: This is the implementation of calc_hpr(); it
+//               assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
-calc_hpr() {
+do_calc_hpr() {
+  if ((_flags & F_hpr_known) != 0) {
+    // Someone else computed it first.
+    return;
+  }
+
   nassertv((_flags & F_is_invalid) == 0);
   nassertv((_flags & F_is_invalid) == 0);
-  check_components();
+  if ((_flags & F_components_known) == 0) {
+    do_calc_components();
+  }
   if ((_flags & F_hpr_known) == 0) {
   if ((_flags & F_hpr_known) == 0) {
     // If we don't know the hpr yet, we must have been given a quat.
     // If we don't know the hpr yet, we must have been given a quat.
     // Decompose it.
     // Decompose it.
@@ -1829,8 +1854,16 @@ calc_hpr() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
 calc_quat() {
 calc_quat() {
+  MutexHolder holder(_lock);
+  if ((_flags & F_quat_known) != 0) {
+    // Someone else computed it first.
+    return;
+  }
+
   nassertv((_flags & F_is_invalid) == 0);
   nassertv((_flags & F_is_invalid) == 0);
-  check_components();
+  if ((_flags & F_components_known) == 0) {
+    do_calc_components();
+  }
   if ((_flags & F_quat_known) == 0) {
   if ((_flags & F_quat_known) == 0) {
     // If we don't know the quat yet, we must have been given a hpr.
     // If we don't know the quat yet, we must have been given a hpr.
     // Decompose it.
     // Decompose it.
@@ -1841,12 +1874,18 @@ calc_quat() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TransformState::calc_mat
+//     Function: TransformState::do_calc_mat
 //       Access: Private
 //       Access: Private
-//  Description: Computes the matrix from the components.
+//  Description: This is the implementation of calc_mat(); it
+//               assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void TransformState::
 void TransformState::
-calc_mat() {
+do_calc_mat() {
+  if ((_flags & F_mat_known) != 0) {
+    // Someone else computed it first.
+    return;
+  }
+
   nassertv((_flags & F_is_invalid) == 0);
   nassertv((_flags & F_is_invalid) == 0);
   if ((_flags & F_is_identity) != 0) {
   if ((_flags & F_is_identity) != 0) {
     _mat = LMatrix4f::ident_mat();
     _mat = LMatrix4f::ident_mat();
@@ -1855,6 +1894,10 @@ calc_mat() {
     // If we don't have a matrix and we're not identity, the only
     // If we don't have a matrix and we're not identity, the only
     // other explanation is that we were constructed via components.
     // other explanation is that we were constructed via components.
     nassertv((_flags & F_components_known) != 0);
     nassertv((_flags & F_components_known) != 0);
+    if ((_flags & F_hpr_known) == 0) {
+      do_calc_hpr();
+    }
+
     compose_matrix(_mat, _scale, _shear, get_hpr(), _pos);
     compose_matrix(_mat, _scale, _shear, get_hpr(), _pos);
   }
   }
   _flags |= F_mat_known;
   _flags |= F_mat_known;

+ 10 - 3
panda/src/pgraph/transformState.h

@@ -30,6 +30,7 @@
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "geomEnums.h"
 #include "geomEnums.h"
 #include "reMutex.h"
 #include "reMutex.h"
+#include "pmutex.h"
 #include "config_pgraph.h"
 #include "config_pgraph.h"
 #include "deletedChain.h"
 #include "deletedChain.h"
 
 
@@ -271,10 +272,13 @@ private:
   INLINE void check_quat() const;
   INLINE void check_quat() const;
   INLINE void check_mat() const;
   INLINE void check_mat() const;
   void calc_singular();
   void calc_singular();
-  void calc_components();
-  void calc_hpr();
+  INLINE void calc_components();
+  void do_calc_components();
+  INLINE void calc_hpr();
+  void do_calc_hpr();
   void calc_quat();
   void calc_quat();
-  void calc_mat();
+  INLINE void calc_mat();
+  void do_calc_mat();
 
 
   INLINE void check_uniform_scale();
   INLINE void check_uniform_scale();
   INLINE void check_uniform_scale2d();
   INLINE void check_uniform_scale2d();
@@ -312,6 +316,9 @@ private:
   
   
   unsigned int _flags;
   unsigned int _flags;
 
 
+  // This mutex protects _flags, and all of the above computed values.
+  Mutex _lock;
+
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);