Blender V4.3
draw_manager_profiling.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10
11#include "BLI_listbase.h"
12#include "BLI_rect.h"
13#include "BLI_string.h"
14
15#include "BKE_global.hh"
16
17#include "BLF_api.hh"
18
19#include "MEM_guardedalloc.h"
20
21#include "draw_manager_c.hh"
22
23#include "GPU_debug.hh"
24#include "GPU_texture.hh"
25
26#include "UI_resources.hh"
27
29
30#define MAX_TIMER_NAME 32
31#define MAX_NESTED_TIMER 8
32#define MIM_RANGE_LEN 8
33#define GPU_TIMER_FALLOFF 0.1
34
35struct DRWTimer {
38 char name[MAX_TIMER_NAME];
39 int lvl; /* Hierarchy level for nested timer. */
40 bool is_query; /* Does this timer actually perform queries or is it just a group. */
41};
42
43static struct DRWTimerPool {
45 int chunk_count; /* Number of chunk allocated. */
46 int timer_count; /* chunk_count * CHUNK_SIZE */
47 int timer_increment; /* Keep track of where we are in the stack. */
48 int end_increment; /* Keep track of bad usage. */
49 bool is_recording; /* Are we in the render loop? */
50 bool is_querying; /* Keep track of bad usage. */
51} DTP = {nullptr};
52
54{
55 if (DTP.timers != nullptr) {
56 // for (int i = 0; i < DTP.timer_count; i++) {
57 // DRWTimer *timer = &DTP.timers[i];
58 // glDeleteQueries(2, timer->query);
59 // }
61 DTP.timers = nullptr;
62 }
63}
64
66{
67 if (G.debug_value > 20 && G.debug_value < 30) {
68 DTP.is_recording = true;
69 }
70
71 if (DTP.is_recording && DTP.timers == nullptr) {
72 DTP.chunk_count = 1;
74 DTP.timers = static_cast<DRWTimer *>(
75 MEM_callocN(sizeof(DRWTimer) * DTP.timer_count, "DRWTimer stack"));
76 }
77 else if (!DTP.is_recording && DTP.timers != nullptr) {
79 }
80
81 DTP.is_querying = false;
84}
85
87{
89 /* Resize the stack. */
92 DTP.timers = static_cast<DRWTimer *>(
94 }
95
96 return &DTP.timers[DTP.timer_increment++];
97}
98
99static void drw_stats_timer_start_ex(const char *name, const bool is_query)
100{
101 if (DTP.is_recording) {
103 STRNCPY(timer->name, name);
105 timer->is_query = is_query;
106
107 /* Queries cannot be nested or interleaved. */
109 if (timer->is_query) {
110 if (timer->query[0] == 0) {
111 // glGenQueries(1, timer->query);
112 }
113
114 // glFinish();
115 /* Issue query for the next frame */
116 // glBeginQuery(GL_TIME_ELAPSED, timer->query[0]);
117 DTP.is_querying = true;
118 }
119 }
120}
121
122void DRW_stats_group_start(const char *name)
123{
124 drw_stats_timer_start_ex(name, false);
125
127}
128
137
138void DRW_stats_query_start(const char *name)
139{
141 drw_stats_timer_start_ex(name, true);
142}
143
145{
147 if (DTP.is_recording) {
150 // glEndQuery(GL_TIME_ELAPSED);
151 DTP.is_querying = false;
152 }
153}
154
156{
158 "You forgot a DRW_stats_group/query_end somewhere!");
160 "You forgot a DRW_stats_group/query_start somewhere!");
161
162 if (DTP.is_recording) {
163 uint64_t lvl_time[MAX_NESTED_TIMER] = {0};
164
165 /* Swap queries for the next frame and sum up each lvl time. */
166 for (int i = DTP.timer_increment - 1; i >= 0; i--) {
167 DRWTimer *timer = &DTP.timers[i];
168 std::swap(timer->query[0], timer->query[1]);
169
171
172 if (timer->is_query) {
173 uint64_t time = 0;
174 if (timer->query[0] != 0) {
175 // glGetQueryObjectui64v(timer->query[0], GL_QUERY_RESULT, &time);
176 }
177 else {
178 time = 1000000000; /* 1ms default */
179 }
180
181 timer->time_average = timer->time_average * (1.0 - GPU_TIMER_FALLOFF) +
182 time * GPU_TIMER_FALLOFF;
183 timer->time_average = std::min(timer->time_average, uint64_t(1000000000));
184 }
185 else {
186 timer->time_average = lvl_time[timer->lvl + 1];
187 lvl_time[timer->lvl + 1] = 0;
188 }
189
190 lvl_time[timer->lvl] += timer->time_average;
191 }
192
193 DTP.is_recording = false;
194 }
195}
196
197static void draw_stat_5row(const rcti *rect, int u, int v, const char *txt, const int size)
198{
199 BLF_draw_default(rect->xmin + (1 + u * 5) * U.widget_unit,
200 rect->ymax - (3 + v) * U.widget_unit,
201 0.0f,
202 txt,
203 size);
204}
205
206static void draw_stat(const rcti *rect, int u, int v, const char *txt, const int size)
207{
209 rect->xmin + (1 + u) * U.widget_unit, rect->ymax - (3 + v) * U.widget_unit, 0.0f, txt, size);
210}
211
212void DRW_stats_draw(const rcti *rect)
213{
214 char stat_string[64];
215 int lvl_index[MAX_NESTED_TIMER];
216 int v = 0, u = 0;
217
218 double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
219
220 int fontid = BLF_default();
223
224 /* ------------------------------------------ */
225 /* ---------------- CPU stats --------------- */
226 /* ------------------------------------------ */
227 /* Label row */
228 char col_label[32];
229 STRNCPY(col_label, "Engine");
230 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
231 STRNCPY(col_label, "Init");
232 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
233 STRNCPY(col_label, "Background");
234 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
235 STRNCPY(col_label, "Render");
236 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
237 STRNCPY(col_label, "Total (w/o cache)");
238 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
239 v++;
240
241 /* Engines rows */
242 char time_to_txt[16];
244 u = 0;
245
246 draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname));
247
248 init_tot_time += data->init_time;
249 SNPRINTF(time_to_txt, "%.2fms", data->init_time);
250 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
251
252 background_tot_time += data->background_time;
253 SNPRINTF(time_to_txt, "%.2fms", data->background_time);
254 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
255
256 render_tot_time += data->render_time;
257 SNPRINTF(time_to_txt, "%.2fms", data->render_time);
258 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
259
260 tot_time += data->init_time + data->background_time + data->render_time;
261 SNPRINTF(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time);
262 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
263 v++;
264 }
265
266 /* Totals row */
267 u = 0;
268 STRNCPY(col_label, "Sub Total");
269 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
270 SNPRINTF(time_to_txt, "%.2fms", init_tot_time);
271 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
272 SNPRINTF(time_to_txt, "%.2fms", background_tot_time);
273 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
274 SNPRINTF(time_to_txt, "%.2fms", render_tot_time);
275 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
276 SNPRINTF(time_to_txt, "%.2fms", tot_time);
277 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
278 v += 2;
279
280 u = 0;
282 STRNCPY(col_label, "Cache Time");
283 draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
284 SNPRINTF(time_to_txt, "%.2fms", *cache_time);
285 draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
286 v += 2;
287
288 /* ------------------------------------------ */
289 /* ---------------- GPU stats --------------- */
290 /* ------------------------------------------ */
291
292 /* Memory Stats */
295
296 STRNCPY(stat_string, "GPU Memory");
297 draw_stat(rect, 0, v, stat_string, sizeof(stat_string));
298 SNPRINTF(stat_string, "%.2fMB", double(tex_mem + vbo_mem) / 1000000.0);
299 draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
300 STRNCPY(stat_string, "Textures");
301 draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
302 SNPRINTF(stat_string, "%.2fMB", double(tex_mem) / 1000000.0);
303 draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
304 STRNCPY(stat_string, "Meshes");
305 draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
306 SNPRINTF(stat_string, "%.2fMB", double(vbo_mem) / 1000000.0);
307 draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
308 v += 1;
309
310 /* GPU Timings */
311 STRNCPY(stat_string, "GPU Render Timings");
312 draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
313
314 for (int i = 0; i < DTP.timer_increment; i++) {
315 double time_ms, time_percent;
316 DRWTimer *timer = &DTP.timers[i];
317 DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : nullptr;
318
319 /* Only display a number of lvl at a time */
320 if ((G.debug_value - 21) < timer->lvl) {
321 continue;
322 }
323
325 lvl_index[timer->lvl] = i;
326
327 time_ms = timer->time_average / 1000000.0;
328
329 if (timer_parent != nullptr) {
330 time_percent = (double(timer->time_average) / double(timer_parent->time_average)) * 100.0;
331 }
332 else {
333 time_percent = 100.0;
334 }
335
336 /* avoid very long number */
337 time_ms = std::min(time_ms, 999.0);
338 time_percent = std::min(time_percent, 100.0);
339
340 SNPRINTF(stat_string, "%s", timer->name);
341 draw_stat(rect, 0 + timer->lvl, v, stat_string, sizeof(stat_string));
342 SNPRINTF(stat_string, "%.2fms", time_ms);
343 draw_stat(rect, 12 + timer->lvl, v, stat_string, sizeof(stat_string));
344 SNPRINTF(stat_string, "%.0f", time_percent);
345 draw_stat(rect, 16 + timer->lvl, v, stat_string, sizeof(stat_string));
346 v++;
347 }
348
350}
void BLF_batch_draw_begin()
Definition blf.cc:517
int BLF_default()
void BLF_batch_draw_end()
Definition blf.cc:530
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL()
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define UNLIKELY(x)
typedef double(DMatrix)[4][4]
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
unsigned int GPU_texture_memory_usage_get()
uint GPU_vertbuf_get_memory_usage()
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
@ TH_TEXT_HI
void UI_FontThemeColor(int fontid, int colorid)
ATTR_WARN_UNUSED_RESULT const BMVert * v
unsigned int U
Definition btGjkEpa3.h:78
DRWManager DST
void DRW_stats_free()
#define MAX_NESTED_TIMER
#define MAX_TIMER_NAME
void DRW_stats_group_start(const char *name)
void DRW_stats_query_start(const char *name)
void DRW_stats_reset()
static struct DRWTimerPool DTP
void DRW_stats_group_end()
void DRW_stats_begin()
void DRW_stats_draw(const rcti *rect)
static DRWTimer * drw_stats_timer_get()
static void drw_stats_timer_start_ex(const char *name, const bool is_query)
void DRW_stats_query_end()
#define GPU_TIMER_FALLOFF
static void draw_stat_5row(const rcti *rect, int u, int v, const char *txt, const int size)
static void draw_stat(const rcti *rect, int u, int v, const char *txt, const int size)
#define MIM_RANGE_LEN
double * DRW_view_data_cache_time_get(DRWViewData *view_data)
#define DRW_ENABLED_ENGINE_ITER(view_data_, engine_, data_)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
unsigned int uint32_t
Definition stdint.h:80
unsigned __int64 uint64_t
Definition stdint.h:90
DRWViewData * view_data_active
int ymax
int xmin
wmTimer * timer