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