Răsfoiți Sursa

collect_vertex_data

David Rose 20 ani în urmă
părinte
comite
d36604ab05

+ 8 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2494,6 +2494,10 @@ draw_tristrips(const qpGeomTristrips *primitive) {
   const unsigned short *client_pointer = setup_primitive(primitive);
 
   if (connect_triangle_strips && _render_mode != RenderModeAttrib::M_wireframe) {
+    GLCAT.debug()
+      << "Connected triangle strips\n";
+    primitive->write(GLCAT.debug(), 2);
+
     // One long triangle strip, connected by the degenerate vertices
     // that have already been set up within the primitive.
     _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices());
@@ -2504,6 +2508,10 @@ draw_tristrips(const qpGeomTristrips *primitive) {
                          GL_UNSIGNED_SHORT, client_pointer);
 
   } else {
+    GLCAT.debug()
+      << "Separate triangle strips\n";
+    primitive->write(GLCAT.debug(), 2);
+
     // Send the individual triangle strips, stepping over the
     // degenerate vertices.
     CPTA_int ends = primitive->get_ends();

+ 39 - 0
panda/src/gobj/qpgeom.cxx

@@ -141,6 +141,45 @@ set_vertex_data(const qpGeomVertexData *data) {
   reset_point_rendering(cdata);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::offset_vertices
+//       Access: Published
+//  Description: Replaces a Geom's vertex table with a new table, and
+//               simultaneously adds the indicated offset to all
+//               vertex references within the Geom's primitives.  This
+//               is intended to be used to combine multiple
+//               GeomVertexDatas from different Geoms into a single
+//               big buffer, with each Geom referencing a subset of
+//               the vertices in the buffer.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+offset_vertices(const qpGeomVertexData *data, int offset) {
+  clear_cache();
+  CDWriter cdata(_cycler);
+  cdata->_data = (qpGeomVertexData *)data;
+
+#ifndef NDEBUG
+  bool all_is_valid = true;
+#endif
+  Primitives::iterator pi;
+  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
+    (*pi)->offset_vertices(offset);
+
+#ifndef NDEBUG
+    if (!(*pi)->check_valid(data)) {
+      all_is_valid = false;
+    }
+#endif
+  }
+
+  cdata->_got_usage_hint = false;
+  cdata->_modified = qpGeom::get_next_modified();
+  mark_bound_stale();
+  reset_point_rendering(cdata);
+
+  nassertv(all_is_valid);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::set_primitive
 //       Access: Published

+ 1 - 0
panda/src/gobj/qpgeom.h

@@ -98,6 +98,7 @@ PUBLISHED:
   INLINE CPT(qpGeomVertexData) get_vertex_data() const;
   PT(qpGeomVertexData) modify_vertex_data();
   void set_vertex_data(const qpGeomVertexData *data);
+  void offset_vertices(const qpGeomVertexData *data, int offset);
 
   INLINE int get_num_primitives() const;
   INLINE const qpGeomPrimitive *get_primitive(int i) const;

+ 22 - 0
panda/src/gobj/qpgeomPrimitive.cxx

@@ -274,6 +274,28 @@ clear_vertices() {
   cdata->_got_minmax = false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::offset_vertices
+//       Access: Published
+//  Description: Adds the indicated offset to all vertices used by the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+offset_vertices(int offset) {
+  clear_cache();
+  CDWriter cdata(_cycler);
+
+  cdata->_rotated_vertices.clear();
+  cdata->_mins.clear();
+  cdata->_maxs.clear();
+  cdata->_got_minmax = false;
+
+  PTA_ushort::iterator vi;
+  for (vi = cdata->_vertices.begin(); vi != cdata->_vertices.end(); ++vi) {
+    (*vi) += offset;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_num_primitives
 //       Access: Published

+ 1 - 0
panda/src/gobj/qpgeomPrimitive.h

@@ -119,6 +119,7 @@ PUBLISHED:
   void add_next_vertices(int num_vertices);
   bool close_primitive();
   void clear_vertices();
+  void offset_vertices(int offset);
 
   int get_num_primitives() const;
   int get_primitive_start(int n) const;

+ 31 - 0
panda/src/gobj/qpgeomVertexFormat.I

@@ -197,6 +197,37 @@ get_vector(int n) const {
   return _vectors[n];
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_num_texcoords
+//       Access: Published
+//  Description: Returns the number of columns within the format
+//               that represent texture coordinates.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexFormat::
+get_num_texcoords() const {
+  nassertr(_is_registered, 0);
+  return _texcoords.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_texcoord
+//       Access: Published
+//  Description: Returns the name of the nth texcoord column.  This
+//               represents a texture coordinate.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+INLINE const InternalName *qpGeomVertexFormat::
+get_texcoord(int n) const {
+  nassertr(_is_registered, NULL);
+  nassertr(n >= 0 && n < (int)_texcoords.size(), NULL);
+  return _texcoords[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexFormat::get_num_morphs
 //       Access: Published

+ 6 - 0
panda/src/gobj/qpgeomVertexFormat.cxx

@@ -546,6 +546,11 @@ do_register() {
       _vectors.push_back(column->get_name());
       break;
 
+    case qpGeomVertexColumn::C_texcoord:
+      // It's a texcoord.
+      _texcoords.push_back(column->get_name());
+      break;
+
     case qpGeomVertexColumn::C_morph_delta:
       {
         // It's a morph description.
@@ -604,6 +609,7 @@ do_unregister() {
   _columns_by_name.clear();
   _points.clear();
   _vectors.clear();
+  _texcoords.clear();
   _morphs.clear();
 }
 

+ 4 - 0
panda/src/gobj/qpgeomVertexFormat.h

@@ -104,6 +104,9 @@ PUBLISHED:
   INLINE int get_num_vectors() const;
   INLINE const InternalName *get_vector(int n) const;
 
+  INLINE int get_num_texcoords() const;
+  INLINE const InternalName *get_texcoord(int n) const;
+
   INLINE int get_num_morphs() const;
   INLINE const InternalName *get_morph_slider(int n) const;
   INLINE const InternalName *get_morph_base(int n) const;
@@ -190,6 +193,7 @@ private:
   typedef pvector< CPT(InternalName) > Columns;
   Columns _points;
   Columns _vectors;
+  Columns _texcoords;
 
   class MorphRecord {
   public:

+ 1 - 1
panda/src/gobj/qpgeomVertexRewriter.I

@@ -159,7 +159,7 @@ set_column(const InternalName *name) {
 //               The return value is true if the data type is valid,
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
-bool qpGeomVertexRewriter::
+INLINE bool qpGeomVertexRewriter::
 set_column(int array, const qpGeomVertexColumn *column) {
   // It's important to invoke the writer first, then the reader.  See
   // set_vertex().

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

@@ -154,6 +154,14 @@ ConfigVariableBool auto_break_cycles
           "is false, you must explicitly call TransformState.clear_cache() "
           "from time to time to prevent gradual memory bloat."));
 
+ConfigVariableInt max_collect_vertices
+("max-collect-vertices", 4096,
+ PRC_DESC("Specifies the maximum number of vertices that are allowed to be "
+          "accumulated into any one GeomVertexData structure as a result "
+          "of collecting objects together during a flatten operation.  This "
+          "does not impose a limit on the original size of any one "
+          "GeomVertexData structure."));
+
 ConfigVariableBool polylight_info
 ("polylight-info", false,
  PRC_DESC("Set this true to view some info statements regarding the polylight. "

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

@@ -23,6 +23,7 @@
 #include "notifyCategoryProxy.h"
 #include "dconfig.h"
 #include "configVariableBool.h"
+#include "configVariableInt.h"
 #include "configVariableDouble.h"
 #include "configVariableList.h"
 
@@ -40,6 +41,7 @@ extern ConfigVariableBool paranoid_compose;
 extern ConfigVariableBool compose_componentwise;
 extern ConfigVariableBool paranoid_const;
 extern ConfigVariableBool auto_break_cycles;
+extern ConfigVariableInt max_collect_vertices;
 
 extern ConfigVariableBool polylight_info;
 extern ConfigVariableDouble lod_fade_time;

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

@@ -17,6 +17,30 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::get_max_collect_vertices
+//       Access: Public
+//  Description: Returns the maximum number of vertices that may be
+//               put into a single GeomVertexData as a result of
+//               collecting multiple objects in collect_vertex_data().
+////////////////////////////////////////////////////////////////////
+INLINE int GeomTransformer::
+get_max_collect_vertices() const {
+  return _max_collect_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::set_max_collect_vertices
+//       Access: Public
+//  Description: Specifies the maximum number of vertices that may be
+//               put into a single GeomVertexData as a result of
+//               collecting multiple objects in collect_vertex_data().
+////////////////////////////////////////////////////////////////////
+INLINE void GeomTransformer::
+set_max_collect_vertices(int max_collect_vertices) {
+  _max_collect_vertices = max_collect_vertices;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTransformer::qpSourceVertices::Ordering Operator
 //       Access: Public
@@ -113,3 +137,19 @@ operator < (const GeomTransformer::SourceColors &other) const {
   }
   return (_scale.compare_to(other._scale) < 0);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::NewCollectedKey::Ordering Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool GeomTransformer::NewCollectedKey::
+operator < (const GeomTransformer::NewCollectedKey &other) const {
+  if (_format != other._format) {
+    return _format < other._format;
+  }
+  if (_usage_hint != other._usage_hint) {
+    return (int)_usage_hint < (int)other._usage_hint;
+  }
+  return _name < other._name;
+}

+ 129 - 1
panda/src/pgraph/geomTransformer.cxx

@@ -28,7 +28,21 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GeomTransformer::
-GeomTransformer() {
+GeomTransformer() :
+  // The default value here comes from the Config file.
+  _max_collect_vertices(max_collect_vertices)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+GeomTransformer::
+GeomTransformer(const GeomTransformer &copy) :
+  _max_collect_vertices(copy._max_collect_vertices)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -510,3 +524,117 @@ apply_state(GeomNode *node, const RenderState *state) {
 
   return any_changed;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::collect_vertex_data
+//       Access: Public
+//  Description: Transforms the vertices and the normals in the
+//               indicated Geom by the indicated matrix.  Returns true
+//               if the Geom was changed, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool GeomTransformer::
+collect_vertex_data(Geom *geom, bool keep_names) {
+  if (!geom->is_of_type(qpGeom::get_class_type())) {
+    return false;
+  }
+
+  qpGeom *qpgeom = DCAST(qpGeom, geom);
+
+  const qpGeomVertexData *vdata = qpgeom->get_vertex_data();
+
+  if (vdata->get_num_vertices() > _max_collect_vertices) {
+    // Don't even bother.
+    return false;
+  }
+
+  const qpGeomVertexFormat *format = vdata->get_format();
+
+  NewCollectedKey key;
+  if (keep_names) {
+    key._name = vdata->get_name();
+  }
+  key._format = format;
+  key._usage_hint = vdata->get_usage_hint();
+
+  AlreadyCollected::const_iterator ai;
+  ai = _already_collected.find(vdata);
+  if (ai != _already_collected.end()) {
+    // We've previously collected this vertex data; reuse it.
+    const AlreadyCollectedData &acd = (*ai).second;
+    qpgeom->offset_vertices(acd._data, acd._offset);
+    return true;
+  }
+
+  // We haven't collected this vertex data yet; append the vertices
+  // onto the new data.
+
+  NewCollectedData::iterator ni = _new_collected_data.find(key);
+  PT(qpGeomVertexData) new_data;
+  if (ni != _new_collected_data.end()) {
+    new_data = (*ni).second;
+  } else {
+    new_data = new qpGeomVertexData(vdata->get_name(), format, 
+                                    vdata->get_usage_hint());
+    _new_collected_data[key] = new_data;
+  }
+
+  int offset = new_data->get_num_vertices();
+  int new_num_vertices = offset + vdata->get_num_vertices();
+  if (new_num_vertices > _max_collect_vertices) {
+    // Whoa, hold the phone!  Too many vertices going into this one
+    // GeomVertexData object; we'd better start over.
+    new_data = new qpGeomVertexData(vdata->get_name(), format, 
+                                    vdata->get_usage_hint());
+    _new_collected_data[key] = new_data;
+    offset = 0;
+    new_num_vertices = vdata->get_num_vertices();
+  }
+
+  new_data->set_num_vertices(new_num_vertices);
+
+  for (int i = 0; i < vdata->get_num_arrays(); ++i) {
+    qpGeomVertexArrayData *new_array = new_data->modify_array(i);
+    const qpGeomVertexArrayData *old_array = vdata->get_array(i);
+    int stride = format->get_array(i)->get_stride();
+    int start_byte = offset * stride;
+    int copy_bytes = old_array->get_data_size_bytes();
+    nassertr(start_byte + copy_bytes == new_array->get_data_size_bytes(), false);
+
+    memcpy(new_array->modify_data() + start_byte,
+           old_array->get_data(), copy_bytes);
+  }
+
+  qpgeom->offset_vertices(new_data, offset);
+  AlreadyCollectedData &acd = _already_collected[vdata];
+  acd._data = new_data;
+  acd._offset = offset;
+
+  return true;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTransformer::collect_vertex_data
+//       Access: Public
+//  Description: Collects together individual GeomVertexData
+//               structures that share the same format into one big
+//               GeomVertexData structure.  This is designed to
+//               minimize context switches on the graphics card.
+////////////////////////////////////////////////////////////////////
+bool GeomTransformer::
+collect_vertex_data(GeomNode *node, bool keep_names) {
+  bool any_changed = false;
+
+  GeomNode::CDWriter cdata(node->_cycler);
+  GeomNode::Geoms::iterator gi;
+  for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
+    GeomNode::GeomEntry &entry = (*gi);
+    PT(Geom) new_geom = entry._geom->make_copy();
+    if (collect_vertex_data(new_geom, keep_names)) {
+      entry._geom = new_geom;
+      any_changed = true;
+    }
+  }
+
+  return any_changed;
+}

+ 28 - 0
panda/src/pgraph/geomTransformer.h

@@ -48,8 +48,12 @@ class InternalName;
 class EXPCL_PANDA GeomTransformer {
 public:
   GeomTransformer();
+  GeomTransformer(const GeomTransformer &copy);
   ~GeomTransformer();
 
+  INLINE int get_max_collect_vertices() const;
+  INLINE void set_max_collect_vertices(int max_collect_vertices);
+
   bool transform_vertices(Geom *geom, const LMatrix4f &mat);
   bool transform_vertices(GeomNode *node, const LMatrix4f &mat);
 
@@ -68,7 +72,12 @@ public:
 
   bool apply_state(GeomNode *node, const RenderState *state);
 
+  bool collect_vertex_data(Geom *geom, bool keep_names);
+  bool collect_vertex_data(GeomNode *node, bool keep_names);
+
 private:
+  int _max_collect_vertices;
+
   class qpSourceVertices {
   public:
     INLINE bool operator < (const qpSourceVertices &other) const;
@@ -153,6 +162,25 @@ private:
   };
   typedef pmap<SourceColors, PTA_Colorf> TColors;
   TColors _tcolors;
+
+  class AlreadyCollectedData {
+  public:
+    CPT(qpGeomVertexData) _data;
+    int _offset;
+  };
+  typedef pmap< CPT(qpGeomVertexData), AlreadyCollectedData> AlreadyCollected;
+  AlreadyCollected _already_collected;
+
+  class NewCollectedKey {
+  public:
+    INLINE bool operator < (const NewCollectedKey &other) const;
+
+    string _name;
+    CPT(qpGeomVertexFormat) _format;
+    qpGeomUsageHint::UsageHint _usage_hint;
+  };
+  typedef pmap< NewCollectedKey, PT(qpGeomVertexData) > NewCollectedData;
+  NewCollectedData _new_collected_data;
 };
 
 #include "geomTransformer.I"

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

@@ -73,3 +73,22 @@ apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
               int attrib_types, GeomTransformer &transformer) {
   r_apply_attribs(node, attribs, attrib_types, transformer);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphReducer::collect_vertex_data
+//       Access: Published
+//  Description: Collects all different GeomVertexData blocks that
+//               have compatible formats at this node and below into a
+//               single, unified block (or at least multiple larger
+//               blocks).  This is intended to reduce rendering
+//               overhead incurred by switching vertex buffers.
+//
+//               The set of bits passed in collect_bits indicates
+//               which properties are used to differentiate
+//               GeomVertexData blocks.  If it is 0, then more blocks
+//               will be combined together than if it is nonzero.
+////////////////////////////////////////////////////////////////////
+INLINE int SceneGraphReducer::
+collect_vertex_data(PandaNode *root, int collect_bits) {
+  return r_collect_vertex_data(root, collect_bits, _transformer);
+}

+ 45 - 1
panda/src/pgraph/sceneGraphReducer.cxx

@@ -19,7 +19,7 @@
 #include "sceneGraphReducer.h"
 #include "config_pgraph.h"
 #include "accumulatedAttribs.h"
-
+#include "modelNode.h"
 #include "pointerTo.h"
 #include "plist.h"
 #include "pmap.h"
@@ -564,3 +564,47 @@ choose_name(PandaNode *preserve, PandaNode *source1, PandaNode *source2) {
     preserve->set_name(name);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: SceneGraphReducer::r_collect_vertex_data
+//       Access: Private
+//  Description: The recursive implementation of
+//               collect_vertex_data().
+////////////////////////////////////////////////////////////////////
+int SceneGraphReducer::
+r_collect_vertex_data(PandaNode *node, int collect_bits,
+                      GeomTransformer &transformer) {
+  int num_collected = 0;
+
+  if ((collect_bits & CVD_model) != 0 &&
+      node->is_of_type(ModelNode::get_class_type())) {
+    // When we come to a model node, start a new collection.
+    GeomTransformer new_transformer(transformer);
+
+    PandaNode::Children children = node->get_children();
+    int num_children = children.get_num_children();
+    for (int i = 0; i < num_children; ++i) {
+      num_collected += 
+        r_collect_vertex_data(children.get_child(i), collect_bits, new_transformer);
+    }
+    return num_collected;
+  }
+
+  if (node->is_geom_node()) {
+    // When we come to geom node, collect.
+    bool keep_names = ((collect_bits & SceneGraphReducer::CVD_name) != 0);
+    if (transformer.collect_vertex_data(DCAST(GeomNode, node), keep_names)) {
+      ++num_collected;
+    }
+  }
+
+  // Then recurse.
+  PandaNode::Children children = node->get_children();
+  int num_children = children.get_num_children();
+  for (int i = 0; i < num_children; ++i) {
+    num_collected +=
+      r_collect_vertex_data(children.get_child(i), collect_bits, transformer);
+  }
+
+  return num_collected;
+}

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

@@ -61,12 +61,19 @@ PUBLISHED:
     CS_recurse         = 0x004,
   };
 
+  enum CollectVertexData {
+    CVD_name           = 0x001,
+    CVD_model          = 0x002,
+  };
+
   INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0);
   INLINE void apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
                             int attrib_types, GeomTransformer &transformer);
 
   int flatten(PandaNode *root, int combine_siblings_bits);
 
+  INLINE int collect_vertex_data(PandaNode *root, int collect_bits = ~0);
+
 protected:
   void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
                        int attrib_types, GeomTransformer &transformer);
@@ -92,6 +99,9 @@ protected:
   void choose_name(PandaNode *preserve, PandaNode *source1, 
                    PandaNode *source2);
 
+  int r_collect_vertex_data(PandaNode *node, int collect_bits,
+                            GeomTransformer &transformer);
+
 private:
   GeomTransformer _transformer;
 };