39 SceneGraphAnalyzer() {
48 ~SceneGraphAnalyzer() {
60 _unique_vdatas.clear();
61 _unique_vadatas.clear();
67 _num_nodes_with_attribs = 0;
71 _num_geom_vertex_datas = 0;
72 _num_geom_vertex_formats = 0;
73 _vertex_data_size = 0;
86 _num_individual_tris = 0;
88 _num_triangles_in_strips = 0;
90 _num_triangles_in_fans = 0;
91 _num_vertices_in_patches = 0;
95 _num_long_normals = 0;
96 _num_short_normals = 0;
97 _total_normal_length = 0.0f;
107 collect_statistics(node,
false);
114 write(std::ostream &out,
int indent_level)
const {
116 << _num_nodes <<
" total nodes (including "
117 << _num_instances <<
" instances); " << _num_lod_nodes <<
" LODNodes.\n";
120 << _num_transforms <<
" transforms";
122 if (_num_nodes != 0) {
123 out <<
"; " << 100 * _num_nodes_with_attribs / _num_nodes
124 <<
"% of nodes have some render attribute.";
129 << _num_geoms <<
" Geoms, with " << _num_geom_vertex_datas
130 <<
" GeomVertexDatas and " << _num_geom_vertex_formats
131 <<
" GeomVertexFormats, appear on " << _num_geom_nodes
134 indent(out, indent_level);
135 if (_num_vertices_64 != 0) {
136 out << _num_vertices_64 <<
" 64-bit vertices, ";
137 if (_num_vertices != _num_vertices_64) {
138 out << _num_vertices - _num_vertices_64 <<
" 32-bit vertices, ";
141 out << _num_vertices <<
" vertices, ";
144 out << _num_normals <<
" normals, "
145 << _num_colors <<
" colors, "
146 << _num_texcoords <<
" texture coordinates.\n";
148 if (_num_long_normals != 0 || _num_short_normals != 0) {
150 << _num_long_normals <<
" normals are too long, "
151 << _num_short_normals <<
" are too short. Average normal length is "
152 << _total_normal_length / (PN_stdfloat)_num_normals <<
"\n";
156 <<
"GeomVertexData arrays occupy " << (_vertex_data_size + 1023) / 1024
160 <<
"GeomPrimitive arrays occupy " << (_prim_data_size + 1023) / 1024
163 int unreferenced_vertices = 0;
164 VDatas::const_iterator vdi;
165 for (vdi = _vdatas.begin(); vdi != _vdatas.end(); ++vdi) {
167 const VDataTracker &tracker = (*vdi).second;
168 int num_unreferenced = vdata->get_num_rows() - tracker._referenced_vertices.get_num_on_bits();
169 nassertv(num_unreferenced >= 0);
170 unreferenced_vertices += num_unreferenced;
172 if (unreferenced_vertices != 0) {
174 << unreferenced_vertices <<
" vertices are unreferenced by any GeomPrimitives.\n";
176 if (_unique_vdatas.size() != _vdatas.size()) {
178 << _vdatas.size() - _unique_vdatas.size()
179 <<
" GeomVertexDatas are redundantly duplicated\n";
181 if (_unique_vadatas.size() != _vadatas.size()) {
182 int wasted_bytes = 0;
184 UniqueVADatas::const_iterator uvai;
185 for (uvai = _unique_vadatas.begin();
186 uvai != _unique_vadatas.end();
189 int dup_count = (*uvai).second;
195 << _vadatas.size() - _unique_vadatas.size()
196 <<
" GeomVertexArrayDatas are redundant, wasting "
197 << (wasted_bytes + 1023) / 1024 <<
"K.\n";
199 if (_unique_prim_vadatas.size() != _prim_vadatas.size()) {
200 int wasted_bytes = 0;
202 UniqueVADatas::const_iterator uvai;
203 for (uvai = _unique_prim_vadatas.begin();
204 uvai != _unique_prim_vadatas.end();
207 int dup_count = (*uvai).second;
213 << _prim_vadatas.size() - _unique_prim_vadatas.size()
214 <<
" GeomPrimitive arrays are redundant, wasting "
215 << (wasted_bytes + 1023) / 1024 <<
"K.\n";
219 << _num_tris <<
" triangles:\n";
220 indent(out, indent_level + 2)
221 << _num_triangles_in_strips
222 <<
" of these are on " << _num_tristrips <<
" tristrips";
223 if (_num_tristrips != 0) {
225 << (double)_num_triangles_in_strips / (
double)_num_tristrips
226 <<
" average tris per strip)";
230 if (_num_trifans != 0) {
231 indent(out, indent_level + 2)
232 << _num_triangles_in_fans
233 <<
" of these are on " << _num_trifans <<
" trifans";
234 if (_num_trifans != 0) {
236 << (double)_num_triangles_in_fans / (
double)_num_trifans
237 <<
" average tris per fan)";
242 indent(out, indent_level + 2)
243 << _num_individual_tris
244 <<
" of these are independent triangles.\n";
246 if (_num_patches != 0) {
248 << _num_patches <<
" patches ("
249 << (double)_num_vertices_in_patches / (
double)_num_patches
250 <<
" average verts per patch).\n";
253 if (_num_lines != 0 || _num_points != 0) {
255 << _num_lines <<
" lines, " << _num_points <<
" points.\n";
259 << _textures.size() <<
" textures, estimated minimum "
260 << (_texture_bytes + 1023) / 1024 <<
"K texture memory required.\n";
266 void SceneGraphAnalyzer::
267 collect_statistics(
PandaNode *node,
bool under_instance) {
270 if (!under_instance) {
271 Nodes::iterator ni = _nodes.find(node);
272 if (ni == _nodes.end()) {
274 _nodes.insert(Nodes::value_type(node, 1));
279 under_instance =
true;
283 if (!node->get_state()->is_empty()) {
284 _num_nodes_with_attribs++;
286 node->get_attrib(TextureAttrib::get_class_slot());
287 if (attrib !=
nullptr) {
294 if (!node->get_transform()->is_identity()) {
299 collect_statistics(DCAST(
GeomNode, node));
311 if (sw >= 0 && sw < node->get_num_children()) {
313 collect_statistics(child, under_instance);
328 for (
int i = 0; i < num_children; i++) {
330 collect_statistics(child, under_instance);
337 void SceneGraphAnalyzer::
338 collect_statistics(
GeomNode *geom_node) {
339 nassertv(geom_node !=
nullptr);
344 _num_geoms += num_geoms;
346 for (
int i = 0; i < num_geoms; i++) {
347 const Geom *geom = geom_node->get_geom(i);
348 collect_statistics(geom);
353 geom_state->get_attrib(TextureAttrib::get_class_slot());
354 if (attrib !=
nullptr) {
366 void SceneGraphAnalyzer::
367 collect_statistics(
const Geom *geom) {
369 std::pair<VDatas::iterator, bool> result = _vdatas.insert(VDatas::value_type(vdata, VDataTracker()));
372 ++_num_geom_vertex_datas;
375 bool format_inserted = _vformats.insert(vformat).second;
376 if (format_inserted) {
378 ++_num_geom_vertex_formats;
381 int &dup_count = (*(_unique_vdatas.insert(UniqueVDatas::value_type(vdata, 0)).first)).second;
384 int num_rows = vdata->get_num_rows();
386 if (format->
has_column(InternalName::get_vertex())) {
387 _num_vertices += num_rows;
390 _num_vertices_64 += num_rows;
393 if (format->
has_column(InternalName::get_normal())) {
394 _num_normals += num_rows;
396 while (!rnormal.is_at_end()) {
397 LVector3f normal = rnormal.get_data3f();
398 float length = normal.length();
399 if (IS_NEARLY_EQUAL(length, 1.0f)) {
401 }
else if (length > 1.0f) {
404 ++_num_short_normals;
406 _total_normal_length += length;
409 if (format->
has_column(InternalName::get_color())) {
410 _num_colors += num_rows;
413 _num_texcoords += num_rows * num_texcoords;
415 int num_arrays = vdata->get_num_arrays();
416 for (
int i = 0; i < num_arrays; ++i) {
417 collect_statistics(vdata->get_array(i));
420 VDataTracker &tracker = (*(result.first)).second;
423 int num_primitives = geom->get_num_primitives();
424 for (
int i = 0; i < num_primitives; ++i) {
427 int num_vertices = prim->get_num_vertices();
428 int strip_cut_index = prim->get_strip_cut_index();
429 for (
int vi = 0; vi < num_vertices; ++vi) {
430 int index = prim->get_vertex(vi);
431 if (index != strip_cut_index) {
432 tracker._referenced_vertices.set_bit(index);
436 if (prim->is_indexed()) {
437 collect_prim_statistics(prim->get_vertices());
438 if (prim->is_composite()) {
439 collect_statistics(prim->get_mins());
440 collect_statistics(prim->get_maxs());
444 if (prim->is_of_type(GeomPoints::get_class_type())) {
445 _num_points += prim->get_num_primitives();
447 }
else if (prim->is_of_type(GeomLines::get_class_type())) {
448 _num_lines += prim->get_num_primitives();
450 }
else if (prim->is_of_type(GeomLinestrips::get_class_type())) {
451 _num_lines += prim->get_num_faces();
453 }
else if (prim->is_of_type(GeomTriangles::get_class_type())) {
454 _num_tris += prim->get_num_primitives();
455 _num_individual_tris += prim->get_num_primitives();
457 }
else if (prim->is_of_type(GeomTristrips::get_class_type())) {
458 _num_tris += prim->get_num_faces();
459 _num_tristrips += prim->get_num_primitives();
460 _num_triangles_in_strips += prim->get_num_faces();
462 }
else if (prim->is_of_type(GeomTrifans::get_class_type())) {
463 _num_tris += prim->get_num_faces();
464 _num_trifans += prim->get_num_primitives();
465 _num_triangles_in_fans += prim->get_num_faces();
467 }
else if (prim->is_of_type(GeomPatches::get_class_type())) {
468 _num_patches += prim->get_num_primitives();
469 _num_vertices_in_patches += prim->get_num_vertices();
473 <<
"Unknown GeomPrimitive type in SceneGraphAnalyzer: "
474 << prim->get_type() <<
"\n";
482 void SceneGraphAnalyzer::
483 collect_statistics(
Texture *texture) {
484 nassertv(texture !=
nullptr);
486 Textures::iterator ti = _textures.find(texture);
487 if (ti == _textures.end()) {
489 _textures.insert(Textures::value_type(texture, 1));
500 _texture_bytes += bytes;
511 void SceneGraphAnalyzer::
513 nassertv(vadata !=
nullptr);
514 bool inserted = _vadatas.insert(vadata).second;
518 int &dup_count = (*(_unique_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
528 void SceneGraphAnalyzer::
530 nassertv(vadata !=
nullptr);
531 bool inserted = _prim_vadatas.insert(vadata).second;
535 int &dup_count = (*(_unique_prim_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;