604792e3254640d4bfbd4c8c5fe768c489ab613d
[blender.git] / source / blender / editors / space_info / info_stats.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup spinfo
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "MEM_guardedalloc.h"
25
26 #include "DNA_armature_types.h"
27 #include "DNA_collection_types.h"
28 #include "DNA_curve_types.h"
29 #include "DNA_gpencil_types.h"
30 #include "DNA_lattice_types.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meta_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_windowmanager_types.h"
35
36 #include "BLI_listbase.h"
37 #include "BLI_math.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "BLT_translation.h"
42
43 #include "BKE_anim.h"
44 #include "BKE_blender_version.h"
45 #include "BKE_curve.h"
46 #include "BKE_displist.h"
47 #include "BKE_key.h"
48 #include "BKE_layer.h"
49 #include "BKE_main.h"
50 #include "BKE_paint.h"
51 #include "BKE_particle.h"
52 #include "BKE_editmesh.h"
53 #include "BKE_object.h"
54 #include "BKE_gpencil.h"
55 #include "BKE_scene.h"
56 #include "BKE_subdiv_ccg.h"
57
58 #include "DEG_depsgraph_query.h"
59
60 #include "ED_info.h"
61 #include "ED_armature.h"
62
63 #include "GPU_extensions.h"
64
65 #define MAX_INFO_LEN 512
66 #define MAX_INFO_NUM_LEN 16
67
68 typedef struct SceneStats {
69   uint64_t totvert, totvertsel;
70   uint64_t totedge, totedgesel;
71   uint64_t totface, totfacesel;
72   uint64_t totbone, totbonesel;
73   uint64_t totobj, totobjsel;
74   uint64_t totlamp, totlampsel;
75   uint64_t tottri;
76   uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
77
78   char infostr[MAX_INFO_LEN];
79 } SceneStats;
80
81 typedef struct SceneStatsFmt {
82   /* Totals */
83   char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN];
84   char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
85   char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN];
86   char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN];
87   char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
88   char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
89   char tottri[MAX_INFO_NUM_LEN];
90   char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
91   char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
92 } SceneStatsFmt;
93
94 static bool stats_mesheval(Mesh *me_eval, bool is_selected, SceneStats *stats)
95 {
96   if (me_eval == NULL) {
97     return false;
98   }
99
100   int totvert, totedge, totface, totloop;
101   if (me_eval->runtime.subdiv_ccg != NULL) {
102     const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
103     BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
104   }
105   else {
106     totvert = me_eval->totvert;
107     totedge = me_eval->totedge;
108     totface = me_eval->totpoly;
109     totloop = me_eval->totloop;
110   }
111
112   stats->totvert += totvert;
113   stats->totedge += totedge;
114   stats->totface += totface;
115   stats->tottri += poly_to_tri_count(totface, totloop);
116
117   if (is_selected) {
118     stats->totvertsel += totvert;
119     stats->totfacesel += totface;
120   }
121   return true;
122 }
123
124 static void stats_object(Object *ob, SceneStats *stats, GSet *objects_gset)
125 {
126   const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
127
128   stats->totobj++;
129   if (is_selected) {
130     stats->totobjsel++;
131   }
132
133   switch (ob->type) {
134     case OB_MESH: {
135       /* we assume evaluated mesh is already built, this strictly does stats now. */
136       Mesh *me_eval = ob->runtime.mesh_eval;
137       if (!BLI_gset_add(objects_gset, me_eval)) {
138         break;
139       }
140       stats_mesheval(me_eval, is_selected, stats);
141       break;
142     }
143     case OB_LAMP:
144       stats->totlamp++;
145       if (is_selected) {
146         stats->totlampsel++;
147       }
148       break;
149     case OB_SURF:
150     case OB_CURVE:
151     case OB_FONT: {
152       Mesh *me_eval = ob->runtime.mesh_eval;
153
154       if ((me_eval != NULL) && !BLI_gset_add(objects_gset, me_eval)) {
155         break;
156       }
157
158       if (stats_mesheval(me_eval, is_selected, stats)) {
159         break;
160       }
161       ATTR_FALLTHROUGH; /* Falltrough to displist. */
162     }
163     case OB_MBALL: {
164       int totv = 0, totf = 0, tottri = 0;
165
166       if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
167         /* Note: We only get the same curve_cache for instances of the same curve/font/...
168          * For simple linked duplicated objects, each has its own dispList. */
169         if (!BLI_gset_add(objects_gset, ob->runtime.curve_cache)) {
170           break;
171         }
172
173         BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri);
174       }
175
176       stats->totvert += totv;
177       stats->totface += totf;
178       stats->tottri += tottri;
179
180       if (is_selected) {
181         stats->totvertsel += totv;
182         stats->totfacesel += totf;
183       }
184       break;
185     }
186     case OB_GPENCIL: {
187       if (is_selected) {
188         bGPdata *gpd = (bGPdata *)ob->data;
189         if (!BLI_gset_add(objects_gset, gpd)) {
190           break;
191         }
192         /* GPXX Review if we can move to other place when object change
193          * maybe to depsgraph evaluation
194          */
195         BKE_gpencil_stats_update(gpd);
196
197         stats->totgplayer += gpd->totlayer;
198         stats->totgpframe += gpd->totframe;
199         stats->totgpstroke += gpd->totstroke;
200         stats->totgppoint += gpd->totpoint;
201       }
202       break;
203     }
204   }
205 }
206
207 static void stats_object_edit(Object *obedit, SceneStats *stats)
208 {
209   if (obedit->type == OB_MESH) {
210     BMEditMesh *em = BKE_editmesh_from_object(obedit);
211
212     stats->totvert += em->bm->totvert;
213     stats->totvertsel += em->bm->totvertsel;
214
215     stats->totedge += em->bm->totedge;
216     stats->totedgesel += em->bm->totedgesel;
217
218     stats->totface += em->bm->totface;
219     stats->totfacesel += em->bm->totfacesel;
220
221     stats->tottri += em->tottri;
222   }
223   else if (obedit->type == OB_ARMATURE) {
224     /* Armature Edit */
225     bArmature *arm = obedit->data;
226     EditBone *ebo;
227
228     for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
229       stats->totbone++;
230
231       if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
232         stats->totvert--;
233       }
234
235       if (ebo->flag & BONE_TIPSEL) {
236         stats->totvertsel++;
237       }
238       if (ebo->flag & BONE_ROOTSEL) {
239         stats->totvertsel++;
240       }
241
242       if (ebo->flag & BONE_SELECTED) {
243         stats->totbonesel++;
244       }
245
246       /* if this is a connected child and it's parent is being moved, remove our root */
247       if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) && ebo->parent &&
248           (ebo->parent->flag & BONE_TIPSEL)) {
249         stats->totvertsel--;
250       }
251
252       stats->totvert += 2;
253     }
254   }
255   else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */
256     /* Curve Edit */
257     Curve *cu = obedit->data;
258     Nurb *nu;
259     BezTriple *bezt;
260     BPoint *bp;
261     int a;
262     ListBase *nurbs = BKE_curve_editNurbs_get(cu);
263
264     for (nu = nurbs->first; nu; nu = nu->next) {
265       if (nu->type == CU_BEZIER) {
266         bezt = nu->bezt;
267         a = nu->pntsu;
268         while (a--) {
269           stats->totvert += 3;
270           if (bezt->f1 & SELECT) {
271             stats->totvertsel++;
272           }
273           if (bezt->f2 & SELECT) {
274             stats->totvertsel++;
275           }
276           if (bezt->f3 & SELECT) {
277             stats->totvertsel++;
278           }
279           bezt++;
280         }
281       }
282       else {
283         bp = nu->bp;
284         a = nu->pntsu * nu->pntsv;
285         while (a--) {
286           stats->totvert++;
287           if (bp->f1 & SELECT) {
288             stats->totvertsel++;
289           }
290           bp++;
291         }
292       }
293     }
294   }
295   else if (obedit->type == OB_MBALL) {
296     /* MetaBall Edit */
297     MetaBall *mball = obedit->data;
298     MetaElem *ml;
299
300     for (ml = mball->editelems->first; ml; ml = ml->next) {
301       stats->totvert++;
302       if (ml->flag & SELECT) {
303         stats->totvertsel++;
304       }
305     }
306   }
307   else if (obedit->type == OB_LATTICE) {
308     /* Lattice Edit */
309     Lattice *lt = obedit->data;
310     Lattice *editlatt = lt->editlatt->latt;
311     BPoint *bp;
312     int a;
313
314     bp = editlatt->def;
315
316     a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
317     while (a--) {
318       stats->totvert++;
319       if (bp->f1 & SELECT) {
320         stats->totvertsel++;
321       }
322       bp++;
323     }
324   }
325 }
326
327 static void stats_object_pose(Object *ob, SceneStats *stats)
328 {
329   if (ob->pose) {
330     bArmature *arm = ob->data;
331     bPoseChannel *pchan;
332
333     for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
334       stats->totbone++;
335       if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
336         if (pchan->bone->layer & arm->layer) {
337           stats->totbonesel++;
338         }
339       }
340     }
341   }
342 }
343
344 static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
345 {
346   stats->totvert = ob->sculpt->bm->totvert;
347   stats->tottri = ob->sculpt->bm->totface;
348 }
349
350 static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode)
351 {
352   return (ob && (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm);
353 }
354
355 /* Statistics displayed in info header. Called regularly on scene changes. */
356 static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
357 {
358   SceneStats stats = {0};
359   Object *ob = OBACT(view_layer);
360   Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
361
362   if (obedit) {
363     /* Edit Mode */
364     FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) {
365       stats_object_edit(ob_iter, &stats);
366     }
367     FOREACH_OBJECT_IN_MODE_END;
368   }
369   else if (ob && (ob->mode & OB_MODE_POSE)) {
370     /* Pose Mode */
371     stats_object_pose(ob, &stats);
372   }
373   else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) {
374     /* Dynamic-topology sculpt mode */
375     stats_object_sculpt_dynamic_topology(ob, &stats);
376   }
377   else {
378     /* Objects */
379     GSet *objects_gset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
380     DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob_iter) {
381       stats_object(ob_iter, &stats, objects_gset);
382     }
383     DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
384     BLI_gset_free(objects_gset, NULL);
385   }
386
387   if (!view_layer->stats) {
388     view_layer->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
389   }
390
391   *(view_layer->stats) = stats;
392 }
393
394 static void stats_string(ViewLayer *view_layer)
395 {
396 #define MAX_INFO_MEM_LEN 64
397   SceneStats *stats = view_layer->stats;
398   SceneStatsFmt stats_fmt;
399   LayerCollection *layer_collection = view_layer->active_collection;
400   Object *ob = OBACT(view_layer);
401   Object *obedit = OBEDIT_FROM_OBACT(ob);
402   eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
403   uintptr_t mem_in_use, mmap_in_use;
404   char memstr[MAX_INFO_MEM_LEN];
405   char gpumemstr[MAX_INFO_MEM_LEN] = "";
406   char formatted_mem[15];
407   char *s;
408   size_t ofs = 0;
409
410   mem_in_use = MEM_get_memory_in_use();
411   mmap_in_use = MEM_get_mapped_memory_in_use();
412
413   /* Generate formatted numbers */
414 #define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
415
416   SCENE_STATS_FMT_INT(totvert);
417   SCENE_STATS_FMT_INT(totvertsel);
418
419   SCENE_STATS_FMT_INT(totedge);
420   SCENE_STATS_FMT_INT(totedgesel);
421
422   SCENE_STATS_FMT_INT(totface);
423   SCENE_STATS_FMT_INT(totfacesel);
424
425   SCENE_STATS_FMT_INT(totbone);
426   SCENE_STATS_FMT_INT(totbonesel);
427
428   SCENE_STATS_FMT_INT(totobj);
429   SCENE_STATS_FMT_INT(totobjsel);
430
431   SCENE_STATS_FMT_INT(totlamp);
432   SCENE_STATS_FMT_INT(totlampsel);
433
434   SCENE_STATS_FMT_INT(tottri);
435
436   SCENE_STATS_FMT_INT(totgplayer);
437   SCENE_STATS_FMT_INT(totgpframe);
438   SCENE_STATS_FMT_INT(totgpstroke);
439   SCENE_STATS_FMT_INT(totgppoint);
440
441 #undef SCENE_STATS_FMT_INT
442
443   /* get memory statistics */
444   BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, true);
445   ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem: %s"), formatted_mem);
446
447   if (mmap_in_use) {
448     BLI_str_format_byte_unit(formatted_mem, mmap_in_use, true);
449     BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%s)"), formatted_mem);
450   }
451
452   if (GPU_mem_stats_supported()) {
453     int gpu_free_mem, gpu_tot_memory;
454
455     GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
456
457     BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, true);
458     ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem: %s"), formatted_mem);
459
460     if (gpu_tot_memory) {
461       BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, true);
462       BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%s"), formatted_mem);
463     }
464   }
465
466   s = stats->infostr;
467   ofs = 0;
468
469   if (object_mode == OB_MODE_OBJECT) {
470     ofs += BLI_snprintf(s + ofs,
471                         MAX_INFO_LEN - ofs,
472                         "%s | ",
473                         BKE_collection_ui_name_get(layer_collection->collection));
474   }
475
476   if (ob) {
477     ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2);
478   }
479
480   if (obedit) {
481     if (BKE_keyblock_from_object(obedit)) {
482       ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs);
483     }
484
485     if (obedit->type == OB_MESH) {
486       ofs += BLI_snprintf(s + ofs,
487                           MAX_INFO_LEN - ofs,
488                           IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
489                           stats_fmt.totvertsel,
490                           stats_fmt.totvert,
491                           stats_fmt.totedgesel,
492                           stats_fmt.totedge,
493                           stats_fmt.totfacesel,
494                           stats_fmt.totface,
495                           stats_fmt.tottri);
496     }
497     else if (obedit->type == OB_ARMATURE) {
498       ofs += BLI_snprintf(s + ofs,
499                           MAX_INFO_LEN - ofs,
500                           IFACE_("Verts:%s/%s | Bones:%s/%s"),
501                           stats_fmt.totvertsel,
502                           stats_fmt.totvert,
503                           stats_fmt.totbonesel,
504                           stats_fmt.totbone);
505     }
506     else {
507       ofs += BLI_snprintf(s + ofs,
508                           MAX_INFO_LEN - ofs,
509                           IFACE_("Verts:%s/%s"),
510                           stats_fmt.totvertsel,
511                           stats_fmt.totvert);
512     }
513
514     ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
515     ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
516   }
517   else if (ob && (object_mode & OB_MODE_POSE)) {
518     ofs += BLI_snprintf(s + ofs,
519                         MAX_INFO_LEN - ofs,
520                         IFACE_("Bones:%s/%s %s%s"),
521                         stats_fmt.totbonesel,
522                         stats_fmt.totbone,
523                         memstr,
524                         gpumemstr);
525   }
526   else if ((ob) && (ob->type == OB_GPENCIL)) {
527     ofs += BLI_snprintf(s + ofs,
528                         MAX_INFO_LEN - ofs,
529                         IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"),
530                         stats_fmt.totgplayer,
531                         stats_fmt.totgpframe,
532                         stats_fmt.totgpstroke,
533                         stats_fmt.totgppoint,
534                         stats_fmt.totobjsel,
535                         stats_fmt.totobj);
536
537     ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
538     ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
539   }
540   else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
541     ofs += BLI_snprintf(s + ofs,
542                         MAX_INFO_LEN - ofs,
543                         IFACE_("Verts:%s | Tris:%s%s"),
544                         stats_fmt.totvert,
545                         stats_fmt.tottri,
546                         gpumemstr);
547   }
548   else {
549     ofs += BLI_snprintf(s + ofs,
550                         MAX_INFO_LEN - ofs,
551                         IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"),
552                         stats_fmt.totvert,
553                         stats_fmt.totface,
554                         stats_fmt.tottri,
555                         stats_fmt.totobjsel,
556                         stats_fmt.totobj,
557                         memstr,
558                         gpumemstr);
559   }
560
561   ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr);
562 #undef MAX_INFO_MEM_LEN
563 }
564
565 #undef MAX_INFO_LEN
566
567 void ED_info_stats_clear(ViewLayer *view_layer)
568 {
569   if (view_layer->stats) {
570     MEM_freeN(view_layer->stats);
571     view_layer->stats = NULL;
572   }
573 }
574
575 const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
576 {
577   /* Loopin through dependency graph when interface is locked in not safe.
578    * Thew interface is marked as locked when jobs wants to modify the
579    * dependency graph. */
580   wmWindowManager *wm = bmain->wm.first;
581   if (wm->is_interface_locked) {
582     return "";
583   }
584   Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
585   if (!view_layer->stats) {
586     stats_update(depsgraph, view_layer);
587   }
588   stats_string(view_layer);
589   return view_layer->stats->infostr;
590 }