Blender  V2.93
draw_manager_profiling.c
Go to the documentation of this file.
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  * Copyright 2016, Blender Foundation.
17  */
18 
23 #include "BLI_listbase.h"
24 #include "BLI_rect.h"
25 #include "BLI_string.h"
26 
27 #include "BKE_global.h"
28 
29 #include "BLF_api.h"
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "draw_manager.h"
34 
35 #include "GPU_debug.h"
36 #include "GPU_texture.h"
37 
38 #include "UI_resources.h"
39 
40 #include "draw_manager_profiling.h"
41 
42 #define MAX_TIMER_NAME 32
43 #define MAX_NESTED_TIMER 8
44 #define CHUNK_SIZE 8
45 #define GPU_TIMER_FALLOFF 0.1
46 
47 typedef struct DRWTimer {
51  int lvl; /* Hierarchy level for nested timer. */
52  bool is_query; /* Does this timer actually perform queries or is it just a group. */
54 
55 static struct DRWTimerPool {
57  int chunk_count; /* Number of chunk allocated. */
58  int timer_count; /* chunk_count * CHUNK_SIZE */
59  int timer_increment; /* Keep track of where we are in the stack. */
60  int end_increment; /* Keep track of bad usage. */
61  bool is_recording; /* Are we in the render loop? */
62  bool is_querying; /* Keep track of bad usage. */
63 } DTP = {NULL};
64 
65 void DRW_stats_free(void)
66 {
67  if (DTP.timers != NULL) {
68  // for (int i = 0; i < DTP.timer_count; i++) {
69  // DRWTimer *timer = &DTP.timers[i];
70  // glDeleteQueries(2, timer->query);
71  // }
73  DTP.timers = NULL;
74  }
75 }
76 
77 void DRW_stats_begin(void)
78 {
79  if (G.debug_value > 20 && G.debug_value < 30) {
80  DTP.is_recording = true;
81  }
82 
83  if (DTP.is_recording && DTP.timers == NULL) {
84  DTP.chunk_count = 1;
86  DTP.timers = MEM_callocN(sizeof(DRWTimer) * DTP.timer_count, "DRWTimer stack");
87  }
88  else if (!DTP.is_recording && DTP.timers != NULL) {
90  }
91 
92  DTP.is_querying = false;
93  DTP.timer_increment = 0;
94  DTP.end_increment = 0;
95 }
96 
98 {
100  /* Resize the stack. */
101  DTP.chunk_count++;
104  }
105 
106  return &DTP.timers[DTP.timer_increment++];
107 }
108 
109 static void drw_stats_timer_start_ex(const char *name, const bool is_query)
110 {
111  if (DTP.is_recording) {
112  DRWTimer *timer = drw_stats_timer_get();
113  BLI_strncpy(timer->name, name, MAX_TIMER_NAME);
114  timer->lvl = DTP.timer_increment - DTP.end_increment - 1;
115  timer->is_query = is_query;
116 
117  /* Queries cannot be nested or interleaved. */
119  if (timer->is_query) {
120  if (timer->query[0] == 0) {
121  // glGenQueries(1, timer->query);
122  }
123 
124  // glFinish();
125  /* Issue query for the next frame */
126  // glBeginQuery(GL_TIME_ELAPSED, timer->query[0]);
127  DTP.is_querying = true;
128  }
129  }
130 }
131 
132 /* Use this to group the queries. It does NOT keep track
133  * of the time, it only sum what the queries inside it. */
134 void DRW_stats_group_start(const char *name)
135 {
136  drw_stats_timer_start_ex(name, false);
137 
138  GPU_debug_group_begin(name);
139 }
140 
142 {
144  if (DTP.is_recording) {
146  DTP.end_increment++;
147  }
148 }
149 
150 /* NOTE: Only call this when no sub timer will be called. */
151 void DRW_stats_query_start(const char *name)
152 {
153  GPU_debug_group_begin(name);
154  drw_stats_timer_start_ex(name, true);
155 }
156 
158 {
160  if (DTP.is_recording) {
161  DTP.end_increment++;
163  // glEndQuery(GL_TIME_ELAPSED);
164  DTP.is_querying = false;
165  }
166 }
167 
168 void DRW_stats_reset(void)
169 {
171  "You forgot a DRW_stats_group/query_end somewhere!");
173  "You forgot a DRW_stats_group/query_start somewhere!");
174 
175  if (DTP.is_recording) {
176  uint64_t lvl_time[MAX_NESTED_TIMER] = {0};
177 
178  /* Swap queries for the next frame and sum up each lvl time. */
179  for (int i = DTP.timer_increment - 1; i >= 0; i--) {
180  DRWTimer *timer = &DTP.timers[i];
181  SWAP(uint32_t, timer->query[0], timer->query[1]);
182 
183  BLI_assert(timer->lvl < MAX_NESTED_TIMER);
184 
185  if (timer->is_query) {
186  uint64_t time = 0;
187  if (timer->query[0] != 0) {
188  // glGetQueryObjectui64v(timer->query[0], GL_QUERY_RESULT, &time);
189  }
190  else {
191  time = 1000000000; /* 1ms default */
192  }
193 
194  timer->time_average = timer->time_average * (1.0 - GPU_TIMER_FALLOFF) +
196  timer->time_average = MIN2(timer->time_average, 1000000000);
197  }
198  else {
199  timer->time_average = lvl_time[timer->lvl + 1];
200  lvl_time[timer->lvl + 1] = 0;
201  }
202 
203  lvl_time[timer->lvl] += timer->time_average;
204  }
205 
206  DTP.is_recording = false;
207  }
208 }
209 
210 static void draw_stat_5row(const rcti *rect, int u, int v, const char *txt, const int size)
211 {
212  BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
213  rect->ymax - (3 + v) * U.widget_unit,
214  0.0f,
215  txt,
216  size);
217 }
218 
219 static void draw_stat(const rcti *rect, int u, int v, const char *txt, const int size)
220 {
222  rect->xmin + (1 + u) * U.widget_unit, rect->ymax - (3 + v) * U.widget_unit, 0.0f, txt, size);
223 }
224 
225 void DRW_stats_draw(const rcti *rect)
226 {
227  char stat_string[64];
228  int lvl_index[MAX_NESTED_TIMER];
229  int v = 0, u = 0;
230 
231  double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
232 
233  int fontid = BLF_default();
234  UI_FontThemeColor(fontid, TH_TEXT_HI);
235  BLF_enable(fontid, BLF_SHADOW);
236  BLF_shadow(fontid, 5, (const float[4]){0.0f, 0.0f, 0.0f, 0.75f});
237  BLF_shadow_offset(fontid, 0, -1);
238 
240 
241  /* ------------------------------------------ */
242  /* ---------------- CPU stats --------------- */
243  /* ------------------------------------------ */
244  /* Label row */
245  char col_label[32];
246  sprintf(col_label, "Engine");
247  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
248  sprintf(col_label, "Init");
249  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
250  sprintf(col_label, "Background");
251  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
252  sprintf(col_label, "Render");
253  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
254  sprintf(col_label, "Total (w/o cache)");
255  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
256  v++;
257 
258  /* Engines rows */
259  char time_to_txt[16];
261  u = 0;
262  DrawEngineType *engine = link->data;
264 
265  draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname));
266 
267  init_tot_time += data->init_time;
268  sprintf(time_to_txt, "%.2fms", data->init_time);
269  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
270 
271  background_tot_time += data->background_time;
272  sprintf(time_to_txt, "%.2fms", data->background_time);
273  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
274 
275  render_tot_time += data->render_time;
276  sprintf(time_to_txt, "%.2fms", data->render_time);
277  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
278 
279  tot_time += data->init_time + data->background_time + data->render_time;
280  sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time);
281  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
282  v++;
283  }
284 
285  /* Totals row */
286  u = 0;
287  sprintf(col_label, "Sub Total");
288  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
289  sprintf(time_to_txt, "%.2fms", init_tot_time);
290  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
291  sprintf(time_to_txt, "%.2fms", background_tot_time);
292  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
293  sprintf(time_to_txt, "%.2fms", render_tot_time);
294  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
295  sprintf(time_to_txt, "%.2fms", tot_time);
296  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
297  v += 2;
298 
299  u = 0;
300  double *cache_time = GPU_viewport_cache_time_get(DST.viewport);
301  sprintf(col_label, "Cache Time");
302  draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
303  sprintf(time_to_txt, "%.2fms", *cache_time);
304  draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
305  v += 2;
306 
307  /* ------------------------------------------ */
308  /* ---------------- GPU stats --------------- */
309  /* ------------------------------------------ */
310 
311  /* Memory Stats */
314 
315  sprintf(stat_string, "GPU Memory");
316  draw_stat(rect, 0, v, stat_string, sizeof(stat_string));
317  sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0);
318  draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
319  sprintf(stat_string, "Textures");
320  draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
321  sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0);
322  draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
323  sprintf(stat_string, "Meshes");
324  draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
325  sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0);
326  draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
327  v += 1;
328 
329  /* GPU Timings */
330  BLI_strncpy(stat_string, "GPU Render Timings", sizeof(stat_string));
331  draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
332 
333  for (int i = 0; i < DTP.timer_increment; i++) {
334  double time_ms, time_percent;
335  DRWTimer *timer = &DTP.timers[i];
336  DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : NULL;
337 
338  /* Only display a number of lvl at a time */
339  if ((G.debug_value - 21) < timer->lvl) {
340  continue;
341  }
342 
343  BLI_assert(timer->lvl < MAX_NESTED_TIMER);
344  lvl_index[timer->lvl] = i;
345 
346  time_ms = timer->time_average / 1000000.0;
347 
348  if (timer_parent != NULL) {
349  time_percent = ((double)timer->time_average / (double)timer_parent->time_average) * 100.0;
350  }
351  else {
352  time_percent = 100.0;
353  }
354 
355  /* avoid very long number */
356  time_ms = MIN2(time_ms, 999.0);
357  time_percent = MIN2(time_percent, 100.0);
358 
359  BLI_snprintf(stat_string, sizeof(stat_string), "%s", timer->name);
360  draw_stat(rect, 0 + timer->lvl, v, stat_string, sizeof(stat_string));
361  BLI_snprintf(stat_string, sizeof(stat_string), "%.2fms", time_ms);
362  draw_stat(rect, 12 + timer->lvl, v, stat_string, sizeof(stat_string));
363  BLI_snprintf(stat_string, sizeof(stat_string), "%.0f", time_percent);
364  draw_stat(rect, 16 + timer->lvl, v, stat_string, sizeof(stat_string));
365  v++;
366  }
367 
369  BLF_disable(fontid, BLF_SHADOW);
370 }
int BLF_default(void)
Definition: blf_default.c:55
void BLF_shadow_offset(int fontid, int x, int y)
Definition: blf.c:841
void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3)
Definition: blf.c:831
void BLF_disable(int fontid, int option)
Definition: blf.c:283
void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL()
Definition: blf_default.c:82
void BLF_batch_draw_begin(void)
Definition: blf.c:470
void BLF_enable(int fontid, int option)
Definition: blf.c:274
#define BLF_SHADOW
Definition: BLF_api.h:271
void BLF_batch_draw_end(void)
Definition: blf.c:483
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNLIKELY(x)
#define MIN2(a, b)
typedef double(DMatrix)[4][4]
void GPU_debug_group_end(void)
Definition: gpu_debug.cc:48
void GPU_debug_group_begin(const char *name)
Definition: gpu_debug.cc:37
unsigned int GPU_texture_memory_usage_get(void)
Definition: gpu_texture.cc:187
uint GPU_vertbuf_get_memory_usage(void)
double * GPU_viewport_cache_time_get(GPUViewport *viewport)
Definition: gpu_viewport.c:351
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
@ TH_TEXT_HI
Definition: UI_resources.h:59
void UI_FontThemeColor(int fontid, int colorid)
Definition: resources.c:1156
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
double time
DRWManager DST
Definition: draw_manager.c:111
void * drw_viewport_engine_data_ensure(void *engine_type)
Definition: draw_manager.c:401
void DRW_stats_query_end(void)
void DRW_stats_begin(void)
#define MAX_NESTED_TIMER
#define MAX_TIMER_NAME
void DRW_stats_group_start(const char *name)
void DRW_stats_query_start(const char *name)
static struct DRWTimerPool DTP
void DRW_stats_reset(void)
void DRW_stats_draw(const rcti *rect)
static void drw_stats_timer_start_ex(const char *name, const bool is_query)
struct DRWTimer DRWTimer
static DRWTimer * drw_stats_timer_get(void)
#define GPU_TIMER_FALLOFF
void DRW_stats_group_end(void)
static void draw_stat_5row(const rcti *rect, int u, int v, const char *txt, const int size)
void DRW_stats_free(void)
static void draw_stat(const rcti *rect, int u, int v, const char *txt, const int size)
#define CHUNK_SIZE
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
unsigned int uint32_t
Definition: stdint.h:83
unsigned __int64 uint64_t
Definition: stdint.h:93
GPUViewport * viewport
Definition: draw_manager.h:521
ListBase enabled_engines
Definition: draw_manager.h:544
char name[MAX_TIMER_NAME]
uint64_t time_average
uint32_t query[2]
char idname[32]
Definition: DRW_render.h:114
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
#define G(x, y, z)