diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index f11022b710..8844c421aa 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -47,11 +47,16 @@ PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage"); PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active"); +PStatCollector GraphicsStateGuardian::_texture_count_pcollector("Prepared Textures"); +PStatCollector GraphicsStateGuardian::_active_texture_count_pcollector("Prepared Textures:Active"); +PStatCollector GraphicsStateGuardian::_total_buffer_count_pcollector("Vertex buffer count"); +PStatCollector GraphicsStateGuardian::_active_vertex_buffer_count_pcollector("Vertex buffer count:Active vertex"); +PStatCollector GraphicsStateGuardian::_active_index_buffer_count_pcollector("Vertex buffer count:Active index"); PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms"); PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active"); -PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffers"); -PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffers:Active vertex"); -PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffers:Active index"); +PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffer size"); +PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffer size:Active vertex"); +PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffer size:Active index"); PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes"); PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active"); PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory"); @@ -1552,6 +1557,8 @@ init_frame_pstats() { _active_geom_node_pcollector.clear_level(); _active_vertex_buffers_pcollector.clear_level(); _active_index_buffers_pcollector.clear_level(); + _active_vertex_buffer_count_pcollector.clear_level(); + _active_index_buffer_count_pcollector.clear_level(); // Also clear out our other counters while we're here. _vertices_tristrip_pcollector.clear_level(); @@ -1606,8 +1613,8 @@ add_to_geom_record(GeomContext *gc) { // Access: Protected // Description: Records that the indicated data array has been drawn // this frame. This function is only used to update the -// PStats active_vertex_buffers collector; it gets compiled out -// if we aren't using PStats. +// PStats active_vertex_buffers collector; it gets +// compiled out if we aren't using PStats. //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: add_to_vertex_buffer_record(VertexBufferContext *vbc) { @@ -1617,6 +1624,7 @@ add_to_vertex_buffer_record(VertexBufferContext *vbc) { if (PStatClient::is_connected()) { if (_current_vertex_buffers.insert(vbc).second) { _active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes()); + _active_vertex_buffer_count_pcollector.add_level(1); } } } @@ -1638,6 +1646,7 @@ add_to_index_buffer_record(IndexBufferContext *ibc) { if (PStatClient::is_connected()) { if (_current_index_buffers.insert(ibc).second) { _active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes()); + _active_index_buffer_count_pcollector.add_level(1); } } } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index a3c7e35d18..f4cd890c57 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -332,6 +332,11 @@ public: // Statistics static PStatCollector _total_texusage_pcollector; static PStatCollector _active_texusage_pcollector; + static PStatCollector _texture_count_pcollector; + static PStatCollector _active_texture_count_pcollector; + static PStatCollector _total_buffer_count_pcollector; + static PStatCollector _active_vertex_buffer_count_pcollector; + static PStatCollector _active_index_buffer_count_pcollector; static PStatCollector _total_geom_pcollector; static PStatCollector _active_geom_pcollector; static PStatCollector _total_buffers_pcollector; diff --git a/panda/src/egg2pg/load_egg_file.cxx b/panda/src/egg2pg/load_egg_file.cxx index c686b7b820..d97fd5370e 100644 --- a/panda/src/egg2pg/load_egg_file.cxx +++ b/panda/src/egg2pg/load_egg_file.cxx @@ -46,6 +46,7 @@ load_from_loader(EggLoader &loader) { SceneGraphReducer gr; int num_reduced = gr.flatten(loader._root, combine_siblings_bits); + // gr.collect_vertex_data(loader._root); egg2pg_cat.info() << "Flattened " << num_reduced << " nodes.\n"; } diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 7fda50d9d6..de3e5e068e 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -27,7 +27,8 @@ #include "mutexHolder.h" PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage"); -PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffers"); +PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer size"); +PStatCollector PreparedGraphicsObjects::_total_buffer_count_pcollector("Vertex buffer count"); //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::Constructor @@ -449,6 +450,7 @@ release_vertex_buffer(VertexBufferContext *vbc) { vbc->_data->clear_prepared(this); _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes()); + _total_buffer_count_pcollector.sub_level(1); // We have to set the Data pointer to NULL at this point, since // the Data itself might destruct at any time after it has been @@ -482,6 +484,7 @@ release_all_vertex_buffers() { VertexBufferContext *vbc = (*vbci); vbc->_data->clear_prepared(this); _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes()); + _total_buffer_count_pcollector.sub_level(1); vbc->_data = (qpGeomVertexArrayData *)NULL; _released_vertex_buffers.insert(vbc); @@ -532,6 +535,7 @@ prepare_vertex_buffer_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase // GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to // count it again here. //_total_buffers_pcollector.add_level(vbc->get_data_size_bytes()); + _total_buffer_count_pcollector.add_level(1); } return vbc; @@ -596,6 +600,7 @@ release_index_buffer(IndexBufferContext *ibc) { ibc->_data->clear_prepared(this); _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes()); + _total_buffer_count_pcollector.sub_level(1); // We have to set the Data pointer to NULL at this point, since // the Data itself might destruct at any time after it has been @@ -629,6 +634,7 @@ release_all_index_buffers() { IndexBufferContext *ibc = (*ibci); ibc->_data->clear_prepared(this); _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes()); + _total_buffer_count_pcollector.sub_level(1); ibc->_data = (qpGeomPrimitive *)NULL; _released_index_buffers.insert(ibc); @@ -679,6 +685,7 @@ prepare_index_buffer_now(qpGeomPrimitive *data, GraphicsStateGuardianBase *gsg) // GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to // count it again here. //_total_buffers_pcollector.add_level(ibc->get_data_size_bytes()); + _total_buffer_count_pcollector.add_level(1); } return ibc; diff --git a/panda/src/gobj/preparedGraphicsObjects.h b/panda/src/gobj/preparedGraphicsObjects.h index f6b39cb606..6a1ae349d2 100644 --- a/panda/src/gobj/preparedGraphicsObjects.h +++ b/panda/src/gobj/preparedGraphicsObjects.h @@ -116,6 +116,7 @@ private: static PStatCollector _total_texusage_pcollector; static PStatCollector _total_buffers_pcollector; + static PStatCollector _total_buffer_count_pcollector; friend class GraphicsStateGuardian; }; diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index cc5534186d..70ba442828 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "geomTransformer.h" +#include "sceneGraphReducer.h" #include "geomNode.h" #include "qpgeom.h" #include "qpgeomVertexRewriter.h" @@ -528,29 +529,23 @@ apply_state(GeomNode *node, const RenderState *state) { //////////////////////////////////////////////////////////////////// // 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. +// Description: Collects together GeomVertexDatas from different +// geoms into one big (or several big) GeomVertexDatas. +// Returns the number of unique GeomVertexDatas created. //////////////////////////////////////////////////////////////////// -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(); +int GeomTransformer:: +collect_vertex_data(qpGeom *geom, int collect_bits) { + const qpGeomVertexData *vdata = geom->get_vertex_data(); if (vdata->get_num_vertices() > _max_collect_vertices) { // Don't even bother. - return false; + return 0; } const qpGeomVertexFormat *format = vdata->get_format(); NewCollectedKey key; - if (keep_names) { + if ((collect_bits & SceneGraphReducer::CVD_name) != 0) { key._name = vdata->get_name(); } key._format = format; @@ -561,12 +556,13 @@ collect_vertex_data(Geom *geom, bool keep_names) { 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; + geom->offset_vertices(acd._data, acd._offset); + return 0; } // We haven't collected this vertex data yet; append the vertices // onto the new data. + int num_created = 0; NewCollectedData::iterator ni = _new_collected_data.find(key); PT(qpGeomVertexData) new_data; @@ -576,6 +572,7 @@ collect_vertex_data(Geom *geom, bool keep_names) { new_data = new qpGeomVertexData(vdata->get_name(), format, vdata->get_usage_hint()); _new_collected_data[key] = new_data; + ++num_created; } int offset = new_data->get_num_vertices(); @@ -588,6 +585,7 @@ collect_vertex_data(Geom *geom, bool keep_names) { _new_collected_data[key] = new_data; offset = 0; new_num_vertices = vdata->get_num_vertices(); + ++num_created; } new_data->set_num_vertices(new_num_vertices); @@ -604,12 +602,12 @@ collect_vertex_data(Geom *geom, bool keep_names) { old_array->get_data(), copy_bytes); } - qpgeom->offset_vertices(new_data, offset); AlreadyCollectedData &acd = _already_collected[vdata]; acd._data = new_data; acd._offset = offset; + geom->offset_vertices(new_data, offset); - return true; + return num_created; } @@ -621,20 +619,38 @@ collect_vertex_data(Geom *geom, bool keep_names) { // 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; +int GeomTransformer:: +collect_vertex_data(GeomNode *node, int collect_bits) { + int num_created = 0; + + GeomTransformer *dynamic = NULL; 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)) { + if (entry._geom->is_of_type(qpGeom::get_class_type())) { + PT(qpGeom) new_geom = DCAST(qpGeom, entry._geom->make_copy()); entry._geom = new_geom; - any_changed = true; + + if ((collect_bits & SceneGraphReducer::CVD_avoid_dynamic) != 0 && + new_geom->get_vertex_data()->get_usage_hint() < qpGeomUsageHint::UH_static) { + // This one has some dynamic properties. Collect it + // independently of the outside world. + if (dynamic == (GeomTransformer *)NULL) { + dynamic = new GeomTransformer(*this); + } + num_created += dynamic->collect_vertex_data(new_geom, collect_bits); + + } else { + num_created += collect_vertex_data(new_geom, collect_bits); + } } } - return any_changed; + if (dynamic != (GeomTransformer *)NULL) { + delete dynamic; + } + + return num_created; } diff --git a/panda/src/pgraph/geomTransformer.h b/panda/src/pgraph/geomTransformer.h index 20c2d1fe2e..1842850f1d 100644 --- a/panda/src/pgraph/geomTransformer.h +++ b/panda/src/pgraph/geomTransformer.h @@ -28,6 +28,7 @@ class GeomNode; class RenderState; class InternalName; +class qpGeom; /////////////////////////////////////////////////////////////////// // Class : GeomTransformer @@ -72,8 +73,8 @@ 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); + int collect_vertex_data(qpGeom *geom, int collect_bits); + int collect_vertex_data(GeomNode *node, int collect_bits); private: int _max_collect_vertices; diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index edb9248f18..b8b3edc31f 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -574,37 +574,50 @@ choose_name(PandaNode *preserve, PandaNode *source1, PandaNode *source2) { int SceneGraphReducer:: r_collect_vertex_data(PandaNode *node, int collect_bits, GeomTransformer &transformer) { - int num_collected = 0; + int num_created = 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. + int this_node_bits = 0; + if (node->is_of_type(ModelNode::get_class_type())) { + this_node_bits |= CVD_model; + } + if (!node->get_transform()->is_identity()) { + this_node_bits |= CVD_transform; + } + + if ((collect_bits & this_node_bits) != 0) { + // We need to start a unique collection here. GeomTransformer new_transformer(transformer); + if (node->is_geom_node()) { + // When we come to geom node, collect. + if (new_transformer.collect_vertex_data(DCAST(GeomNode, node), collect_bits)) { + ++num_created; + } + } + PandaNode::Children children = node->get_children(); int num_children = children.get_num_children(); for (int i = 0; i < num_children; ++i) { - num_collected += + num_created += 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; + } else { + // Keep the same collection. + + if (node->is_geom_node()) { + if (transformer.collect_vertex_data(DCAST(GeomNode, node), collect_bits)) { + ++num_created; + } + } + + PandaNode::Children children = node->get_children(); + int num_children = children.get_num_children(); + for (int i = 0; i < num_children; ++i) { + num_created += + r_collect_vertex_data(children.get_child(i), collect_bits, transformer); } } - - // 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; + + return num_created; } diff --git a/panda/src/pgraph/sceneGraphReducer.h b/panda/src/pgraph/sceneGraphReducer.h index 2c48f6ff5c..cadff14901 100644 --- a/panda/src/pgraph/sceneGraphReducer.h +++ b/panda/src/pgraph/sceneGraphReducer.h @@ -62,8 +62,25 @@ PUBLISHED: }; enum CollectVertexData { + // If set, two GeomVertexDatas with different names will not be + // collected together. CVD_name = 0x001, + + // If set, a ModelNode begins a subgraph of nodes whose + // GeomVertexDatas will not be collected with nodes outside the + // subgraph. CVD_model = 0x002, + + // If set, a non-identity transform begins a subgraph of nodes + // whose GeomVertexDatas will not be collected with nodes outside + // the subgraph. + CVD_transform = 0x004, + + // If set, GeomVertexDatas with any usage_hint other than + // UH_static will not be collected with any other Geoms in a + // different GeomNode. However, two different Geoms within the + // same node might still be collected together. + CVD_avoid_dynamic = 0x008, }; INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0); diff --git a/panda/src/pstatclient/pStatProperties.cxx b/panda/src/pstatclient/pStatProperties.cxx index c0221926f6..056fe64487 100644 --- a/panda/src/pstatclient/pStatProperties.cxx +++ b/panda/src/pstatclient/pStatProperties.cxx @@ -151,13 +151,18 @@ static LevelCollectorProperties level_properties[] = { { 1, "Texture memory:In use", { 0.0, 1.0, 1.0 } }, { 1, "Texture manager", { 1.0, 0.0, 0.0 }, "MB", 12, 1048576 }, { 1, "Texture manager:Resident", { 1.0, 1.0, 0.0 } }, + { 1, "Prepared Textures", { 0.6, 0.8, 0.0 }, "", 500 }, + { 1, "Prepared Textures:Active", { 0.0, 0.6, 0.8 } }, { 1, "Prepared Geoms", { 1.0, 0.0, 0.5 }, "", 500 }, { 1, "Prepared Geoms:Active", { 0.5, 1.0, 0.8 } }, { 1, "Prepared GeomNodes", { 1.0, 0.0, 0.5 }, "", 500 }, { 1, "Prepared GeomNodes:Active", { 0.5, 1.0, 0.8 } }, - { 1, "Vertex buffers:Active vertex", { 1.0, 0.0, 0.5 } }, - { 1, "Vertex buffers:Active index" , { 0.5, 0.6, 1.0 } }, - { 1, "Vertex buffers", { 0.0, 0.0, 1.0 }, "MB", 12, 1048576 }, + { 1, "Vertex buffer size", { 0.0, 0.0, 1.0 }, "MB", 12, 1048576 }, + { 1, "Vertex buffer size:Active vertex", { 1.0, 0.0, 0.5 } }, + { 1, "Vertex buffer size:Active index" , { 0.5, 0.6, 1.0 } }, + { 1, "Vertex buffer count", { 0.0, 0.6, 0.8 }, "", 500 }, + { 1, "Vertex buffer count:Active vertex", { 0.8, 0.0, 0.6 } }, + { 1, "Vertex buffer count:Active index", { 0.8, 0.6, 0.3 } }, { 1, "Vertices", { 0.5, 0.2, 0.0 }, "K", 10, 1000 }, { 1, "Vertices:Other", { 0.2, 0.2, 0.2 } }, { 1, "Vertices:Triangles", { 0.8, 0.8, 0.8 } },