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