Browse Source

allow-live-flatten

David Rose 17 years ago
parent
commit
621b831913

+ 77 - 0
panda/src/display/graphicsEngine.cxx

@@ -53,6 +53,8 @@
   #include <sys/time.h>
 #endif
 
+PT(GraphicsEngine) GraphicsEngine::_global_ptr;
+
 PStatCollector GraphicsEngine::_wait_pcollector("Wait:Thread sync");
 PStatCollector GraphicsEngine::_cycle_pcollector("App:Cycle");
 PStatCollector GraphicsEngine::_app_pcollector("App:Show code:General");
@@ -957,6 +959,20 @@ extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
   }
 }
  
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::get_global_ptr
+//       Access: Published, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+GraphicsEngine *GraphicsEngine::
+get_global_ptr() {
+  if (_global_ptr == NULL) {
+    _global_ptr = new GraphicsEngine;
+    PandaNode::set_scene_root_func(&scene_root_func);
+  }
+  return _global_ptr;
+}
+ 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::add_callback
 //       Access: Public
@@ -1004,6 +1020,67 @@ remove_callback(const string &thread_name,
   return wr->remove_callback(callback_time, Callback(func, data));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::scene_root_func
+//       Access: Private, Static
+//  Description: This function is added to PandaNode::scene_root_func
+//               to implement PandaNode::is_scene_root().
+////////////////////////////////////////////////////////////////////
+bool GraphicsEngine::
+scene_root_func(const PandaNode *node) {
+  return _global_ptr->is_scene_root(node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::is_scene_root
+//       Access: Private
+//  Description: Returns true if the indicated node is known to be
+//               the render root of some active DisplayRegion
+//               associated with this GraphicsEngine, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool GraphicsEngine::
+is_scene_root(const PandaNode *node) {
+  Thread *current_thread = Thread::get_current_thread();
+
+  Windows::const_iterator wi;
+  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
+    GraphicsOutput *win = (*wi);
+    if (win->is_active() && win->get_gsg()->is_active()) {
+      int num_display_regions = win->get_num_active_display_regions();
+      for (int i = 0; i < num_display_regions; i++) {
+        DisplayRegion *dr = win->get_active_display_region(i);
+        if (dr != (DisplayRegion *)NULL) {
+          NodePath camera = dr->get_camera();
+          if (camera.is_empty()) {
+            continue;
+          }
+
+          Camera *camera_node;
+          DCAST_INTO_R(camera_node, camera.node(), NULL);
+          if (!camera_node->is_active()) {
+            continue;
+            return NULL;
+          }
+
+          NodePath scene_root = camera_node->get_scene();
+          if (scene_root.is_empty()) {
+            // If there's no explicit scene specified, use whatever scene the
+            // camera is parented within.  This is the normal and preferred
+            // case; the use of an explicit scene is now deprecated.
+            scene_root = camera.get_top(current_thread);
+          }
+
+          if (scene_root.node() == node) {
+            return true;
+          }
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::set_window_sort
 //       Access: Private

+ 9 - 2
panda/src/display/graphicsEngine.h

@@ -31,6 +31,7 @@
 #include "ordered_vector.h"
 #include "indirectLess.h"
 #include "loader.h"
+#include "referenceCount.h"
 
 class Pipeline;
 class DisplayRegion;
@@ -53,7 +54,7 @@ class Texture;
 //               simply calls engine->render_frame() and considers it
 //               done.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_DISPLAY GraphicsEngine {
+class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount {
 PUBLISHED:
   GraphicsEngine(Pipeline *pipeline = NULL);
   ~GraphicsEngine();
@@ -100,6 +101,8 @@ PUBLISHED:
 
   bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg);
 
+  static GraphicsEngine *get_global_ptr();
+
 public:
   enum ThreadState {
     TS_wait,
@@ -123,7 +126,6 @@ public:
                     CallbackFunction *func, void *data);
   bool remove_callback(const string &thread_name, CallbackTime callback_time,
                        CallbackFunction *func, void *data);
-
   
 private:
   class Callback {
@@ -141,6 +143,9 @@ private:
   typedef pset< PT(GraphicsStateGuardian) > GSGs;
   typedef pset< Callback > Callbacks;
 
+  static bool scene_root_func(const PandaNode *node);
+  bool is_scene_root(const PandaNode *node);
+
   void set_window_sort(GraphicsOutput *window, int sort);
 
   void cull_and_draw_together(const Windows &wlist, Thread *current_thread);
@@ -340,6 +345,8 @@ private:
 
   ReMutex _lock;
 
+  static PT(GraphicsEngine) _global_ptr;
+
   static PStatCollector _wait_pcollector;
   static PStatCollector _cycle_pcollector;
   static PStatCollector _app_pcollector;

+ 2 - 1
panda/src/distort/nonlinearImager.h

@@ -26,6 +26,7 @@
 #include "nodePath.h"
 #include "pointerTo.h"
 #include "pvector.h"
+#include "graphicsEngine.h"
 
 class GraphicsEngine;
 class GraphicsStateGuardian;
@@ -168,7 +169,7 @@ private:
   Viewers _viewers;
   Screens _screens;
 
-  GraphicsEngine *_engine;
+  PT(GraphicsEngine) _engine;
   NodePath _dark_room;
 
   bool _stale;

+ 9 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -353,6 +353,15 @@ ConfigVariableEnum<LODNodeType> default_lod_type
  PRC_DESC("Set this to either 'pop' or 'fade' to determine the type of "
           "LODNode that is created by LODNode::make_default_lod()."));
 
+ConfigVariableBool allow_live_flatten
+("allow-live-flatten", true,
+ PRC_DESC("Set this true to allow the use of flatten_strong() or any "
+          "variant on a node that is attached to a live scene graph node, "
+          "or false to disallow this.  Flattening a live scene graph node "
+          "can cause problems when threading is enabled.  This variable "
+          "only has an effect when Panda is not compiled for a release "
+          "build."));
+
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libpgraph
 //  Description: Initializes the library.  This must be called at

+ 1 - 0
panda/src/pgraph/config_pgraph.h

@@ -72,6 +72,7 @@ extern ConfigVariableList load_file_type;
 extern ConfigVariableString default_model_extension;
 
 extern ConfigVariableEnum<LODNodeType> default_lod_type;
+extern ConfigVariableBool allow_live_flatten;
 
 extern EXPCL_PANDA_PGRAPH void init_libpgraph();
 

+ 24 - 0
panda/src/pgraph/nodePath.cxx

@@ -344,6 +344,30 @@ reparent_to(const NodePath &other, int sort, Thread *current_thread) {
   nassertv(reparented);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::stash_to
+//       Access: Published
+//  Description: Similar to reparent_to(), but the node is added to
+//               its new parent's stashed list, so that the result is
+//               equivalent to calling reparent_to() immediately
+//               followed by stash().
+////////////////////////////////////////////////////////////////////
+void NodePath::
+stash_to(const NodePath &other, int sort, Thread *current_thread) {
+  nassertv(verify_complete());
+  nassertv(other.verify_complete());
+  nassertv_always(!is_empty());
+  nassertv(other._error_type == ET_ok);
+
+  // Reparenting implicitly resets the delta vector.
+  node()->reset_prev_transform();
+
+  int pipeline_stage = current_thread->get_pipeline_stage();
+  bool reparented = PandaNode::reparent(other._head, _head, sort, true,
+					pipeline_stage, current_thread);
+  nassertv(reparented);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::wrt_reparent_to
 //       Access: Published

+ 2 - 0
panda/src/pgraph/nodePath.h

@@ -220,6 +220,8 @@ PUBLISHED:
   // will be arranged in the order they were added.
   void reparent_to(const NodePath &other, int sort = 0,
                    Thread *current_thread = Thread::get_current_thread());
+  void stash_to(const NodePath &other, int sort = 0,
+                Thread *current_thread = Thread::get_current_thread());
   void wrt_reparent_to(const NodePath &other, int sort = 0,
                        Thread *current_thread = Thread::get_current_thread());
   NodePath instance_to(const NodePath &other, int sort = 0,

+ 64 - 0
panda/src/pgraph/pandaNode.cxx

@@ -33,6 +33,8 @@
 NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
 NotifyCategoryDef(drawmask, "");
 
+PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
+
 PandaNodeChain PandaNode::_dirty_prev_transforms;
 DrawMask PandaNode::_overall_bit = DrawMask::bit(31);
 
@@ -2130,6 +2132,53 @@ prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state) {
   r_prepare_scene(net_state, prepared_objects, current_thread);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::is_scene_root
+//       Access: Published
+//  Description: Returns true if this particular node is known to be
+//               the render root of some active DisplayRegion
+//               associated with the global GraphicsEngine, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool PandaNode::
+is_scene_root() const {
+  // This function pointer has to be filled in when the global
+  // GraphicsEngine is created, because we can't link with the
+  // GraphicsEngine functions directly.
+  if (_scene_root_func != (SceneRootFunc *)NULL) {
+    return (*_scene_root_func)(this);
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::is_under_scene_root
+//       Access: Published
+//  Description: Returns true if this particular node is in a live
+//               scene graph: that is, it is a child or descendent of
+//               a node that is itself a scene root.  If this is true,
+//               this node may potentially be traversed by the render
+//               traverser.  Stashed nodes don't count for this
+//               purpose, but hidden nodes do.
+////////////////////////////////////////////////////////////////////
+bool PandaNode::
+is_under_scene_root() const {
+  if (is_scene_root()) {
+    return true;
+  }
+
+  Parents parents = get_parents();
+  for (int i = 0; i < parents.get_num_parents(); ++i) {
+    PandaNode *parent = parents.get_parent(i);
+    if (parent->find_stashed((PandaNode *)this) == -1) {
+      if (parent->is_under_scene_root()) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::output
 //       Access: Published, Virtual
@@ -3832,6 +3881,21 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
   } while (true);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::set_scene_root_func
+//       Access: Public, Static
+//  Description: This is used by the GraphicsEngine to hook in a
+//               pointer to the scene_root_func(), the function to
+//               determine whether the node is an active scene root.
+//               This back-pointer is necessary because we can't make
+//               calls directly into GraphicsEngine, which is in the
+//               display module.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+set_scene_root_func(SceneRootFunc *func) {
+  _scene_root_func = func;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::register_with_read_factory
 //       Access: Public, Static

+ 9 - 0
panda/src/pgraph/pandaNode.h

@@ -242,6 +242,9 @@ PUBLISHED:
 
   void prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state);
 
+  bool is_scene_root() const;
+  bool is_under_scene_root() const;
+
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
 
@@ -671,6 +674,12 @@ public:
   INLINE Stashed get_stashed(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE Parents get_parents(Thread *current_thread = Thread::get_current_thread()) const;
 
+  typedef bool SceneRootFunc(const PandaNode *);
+  static void set_scene_root_func(SceneRootFunc *func);
+
+private:
+  static SceneRootFunc *_scene_root_func;
+
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 6 - 0
panda/src/pgraph/sceneGraphReducer.I

@@ -97,6 +97,7 @@ get_combine_radius() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void SceneGraphReducer::
 apply_attribs(PandaNode *node, int attrib_types) {
+  nassertv(check_live_flatten(node));
   nassertv(node != (PandaNode *)NULL);
   PStatTimer timer(_apply_collector);
   AccumulatedAttribs attribs;
@@ -145,6 +146,7 @@ apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
 INLINE int SceneGraphReducer::
 make_compatible_format(PandaNode *root, int collect_bits) {
   nassertr(root != (PandaNode *)NULL, 0);
+  nassertr(check_live_flatten(root), 0);
   PStatTimer timer(_collect_collector);
   int count = 0;
   count += r_collect_vertex_data(root, collect_bits, _transformer, true);
@@ -171,6 +173,7 @@ make_compatible_format(PandaNode *root, int collect_bits) {
 INLINE int SceneGraphReducer::
 collect_vertex_data(PandaNode *root, int collect_bits) {
   nassertr(root != (PandaNode *)NULL, 0);
+  nassertr(check_live_flatten(root), 0);
   PStatTimer timer(_collect_collector);
   int count = 0;
   count += r_collect_vertex_data(root, collect_bits, _transformer, false);
@@ -191,6 +194,7 @@ collect_vertex_data(PandaNode *root, int collect_bits) {
 INLINE int SceneGraphReducer::
 make_nonindexed(PandaNode *root, int nonindexed_bits) {
   nassertr(root != (PandaNode *)NULL, 0);
+  nassertr(check_live_flatten(root), 0);
   PStatTimer timer(_make_nonindexed_collector);
   return r_make_nonindexed(root, nonindexed_bits);
 }
@@ -209,8 +213,10 @@ make_nonindexed(PandaNode *root, int nonindexed_bits) {
 INLINE void SceneGraphReducer::
 premunge(PandaNode *root, const RenderState *initial_state) {
   nassertv(root != (PandaNode *)NULL);
+  nassertv(check_live_flatten(root));
   if (_gsg != (GraphicsStateGuardianBase *)NULL) {
     PStatTimer timer(_premunge_collector);
     r_premunge(root, initial_state);
   }
 }
+

+ 52 - 15
panda/src/pgraph/sceneGraphReducer.cxx

@@ -97,6 +97,8 @@ clear_gsg() {
 ////////////////////////////////////////////////////////////////////
 int SceneGraphReducer::
 flatten(PandaNode *root, int combine_siblings_bits) {
+  nassertr(check_live_flatten(root), 0);
+
   PStatTimer timer(_flatten_collector);
   int num_total_nodes = 0;
   int num_pass_nodes;
@@ -141,6 +143,8 @@ flatten(PandaNode *root, int combine_siblings_bits) {
 ////////////////////////////////////////////////////////////////////
 int SceneGraphReducer::
 remove_column(PandaNode *root, const InternalName *column) {
+  nassertr(check_live_flatten(root), 0);
+
   PStatTimer timer(_remove_column_collector);
   int count = r_remove_column(root, column, _transformer);
   _transformer.finish_apply();
@@ -158,12 +162,38 @@ remove_column(PandaNode *root, const InternalName *column) {
 ////////////////////////////////////////////////////////////////////
 int SceneGraphReducer::
 make_compatible_state(PandaNode *root) {
+  nassertr(check_live_flatten(root), 0);
+
   PStatTimer timer(_compatible_state_collector);
   int count = r_make_compatible_state(root, _transformer);
   _transformer.finish_apply();
   return count;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphReducer::decompose
+//       Access: Published
+//  Description: Calls decompose() on every GeomNode at this level and
+//               below.
+//
+//               There is usually no reason to call this explicitly,
+//               since unify() will do this anyway if it needs to be
+//               done.  However, calling it ahead of time can make
+//               that future call to unify() run a little bit faster.
+//
+//               This operation has no effect if the config variable
+//               preserve-triangle-strips has been set true.
+////////////////////////////////////////////////////////////////////
+void SceneGraphReducer::
+decompose(PandaNode *root) {
+  nassertv(check_live_flatten(root));
+
+  if (!preserve_triangle_strips) {
+    PStatTimer timer(_unify_collector);
+    r_decompose(root);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SceneGraphReducer::unify
 //       Access: Published
@@ -175,6 +205,7 @@ make_compatible_state(PandaNode *root) {
 ////////////////////////////////////////////////////////////////////
 void SceneGraphReducer::
 unify(PandaNode *root, bool preserve_order) {
+  nassertv(check_live_flatten(root));
   PStatTimer timer(_unify_collector);
 
   int max_indices = max_collect_indices;
@@ -196,6 +227,7 @@ unify(PandaNode *root, bool preserve_order) {
 ////////////////////////////////////////////////////////////////////
 void SceneGraphReducer::
 remove_unused_vertices(PandaNode *root) {
+  nassertv(check_live_flatten(root));
   PStatTimer timer(_remove_unused_collector);
 
   r_register_vertices(root, _transformer);
@@ -204,25 +236,30 @@ remove_unused_vertices(PandaNode *root) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SceneGraphReducer::decompose
+//     Function: SceneGraphReducer::check_live_flatten
 //       Access: Published
-//  Description: Calls decompose() on every GeomNode at this level and
-//               below.
-//
-//               There is usually no reason to call this explicitly,
-//               since unify() will do this anyway if it needs to be
-//               done.  However, calling it ahead of time can make
-//               that future call to unify() run a little bit faster.
+//  Description: In a non-release build, returns false if the node is
+//               correctly not in a live scene graph.  (Calling
+//               flatten on a node that is part of a live scene graph,
+//               for instance, a node somewhere under render, can
+//               cause problems in a multithreaded environment.)
 //
-//               This operation has no effect if the config variable
-//               preserve-triangle-strips has been set true.
+//               If allow_live_flatten is true, or in a release build,
+//               this always returns true.
 ////////////////////////////////////////////////////////////////////
-void SceneGraphReducer::
-decompose(PandaNode *root) {
-  if (!preserve_triangle_strips) {
-    PStatTimer timer(_unify_collector);
-    r_decompose(root);
+bool SceneGraphReducer::
+check_live_flatten(PandaNode *node) {
+#ifndef NDEBUG
+  if (allow_live_flatten) {
+    return true;
   }
+
+  if (node->is_under_scene_root()) {
+    return false;
+  }
+
+#endif  // NDEBUG
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/pgraph/sceneGraphReducer.h

@@ -146,6 +146,7 @@ PUBLISHED:
   void remove_unused_vertices(PandaNode *root);
 
   INLINE void premunge(PandaNode *root, const RenderState *initial_state);
+  bool check_live_flatten(PandaNode *node);
 
 protected:
   void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,