Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/intern/DRW_render.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c129
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c242
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h43
5 files changed, 326 insertions, 92 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 4098cfe696e..e3a3ac499a1 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -63,6 +63,7 @@ set(SRC
intern/draw_common.c
intern/draw_manager.c
intern/draw_manager_text.c
+ intern/draw_manager_profiling.c
intern/draw_view.c
modes/edit_armature_mode.c
modes/edit_curve_mode.c
@@ -94,6 +95,7 @@ set(SRC
intern/draw_cache_impl.h
intern/draw_common.h
intern/draw_manager_text.h
+ intern/draw_manager_profiling.h
intern/draw_view.h
modes/draw_mode_engines.h
engines/basic/basic_engine.h
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index ca6a89f174a..853f2d123eb 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -49,6 +49,8 @@
#include "draw_cache.h"
#include "draw_view.h"
+#include "draw_manager_profiling.h"
+
#include "MEM_guardedalloc.h"
#include "RE_engine.h"
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 70e9d985e6c..00a28f0371a 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -80,6 +80,7 @@
#include "WM_types.h"
#include "draw_manager_text.h"
+#include "draw_manager_profiling.h"
/* only for callbacks */
#include "draw_cache_impl.h"
@@ -191,12 +192,6 @@ struct DRWPass {
ListBase shgroups; /* DRWShadingGroup */
DRWState state;
char name[MAX_PASS_NAME];
- /* use two query to not stall the cpu waiting for queries to complete */
- unsigned int timer_queries[2];
- /* alternate between front and back query */
- unsigned int front_idx;
- unsigned int back_idx;
- bool wasdrawn; /* if it was drawn during this frame */
};
typedef struct DRWCallHeader {
@@ -1260,7 +1255,6 @@ void DRW_pass_free(DRWPass *pass)
DRW_shgroup_free(shgroup);
}
- glDeleteQueries(2, pass->timer_queries);
BLI_freelistN(&pass->shgroups);
}
@@ -1900,28 +1894,7 @@ static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWSha
DRW_state_set(pass->state);
BLI_listbase_clear(&DST.bound_texs);
- /* Init Timer queries */
- if (pass->timer_queries[0] == 0) {
- pass->front_idx = 0;
- pass->back_idx = 1;
-
- glGenQueries(2, pass->timer_queries);
-
- /* dummy query, avoid gl error */
- glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->front_idx]);
- glEndQuery(GL_TIME_ELAPSED);
- }
- else {
- /* swap indices */
- unsigned int tmp = pass->back_idx;
- pass->back_idx = pass->front_idx;
- pass->front_idx = tmp;
- }
-
- if (!pass->wasdrawn) {
- /* issue query for the next frame */
- glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->back_idx]);
- }
+ DRW_stats_query_start(pass->name);
for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) {
draw_shgroup(shgroup, pass->state);
@@ -1943,11 +1916,7 @@ static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWSha
DST.shader = NULL;
}
- if (!pass->wasdrawn) {
- glEndQuery(GL_TIME_ELAPSED);
- }
-
- pass->wasdrawn = true;
+ DRW_stats_query_end();
}
void DRW_draw_pass(DRWPass *pass)
@@ -2620,15 +2589,18 @@ static void DRW_engines_draw_background(void)
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
- double stime = PIL_check_seconds_timer();
if (engine->draw_background) {
+ double stime = PIL_check_seconds_timer();
+
+ DRW_stats_group_start(engine->idname);
engine->draw_background(data);
+ DRW_stats_group_end();
+
+ double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
+ data->background_time = data->background_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
return;
}
-
- double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
- data->background_time = data->background_time * (1.0f - TIMER_FALLOFF) + ftime * TIMER_FALLOFF; /* exp average */
}
/* No draw_background found, doing default background */
@@ -2643,7 +2615,9 @@ static void DRW_engines_draw_scene(void)
double stime = PIL_check_seconds_timer();
if (engine->draw_scene) {
+ DRW_stats_group_start(engine->idname);
engine->draw_scene(data);
+ DRW_stats_group_end();
}
double ftime = (PIL_check_seconds_timer() - stime) * 1e3;
@@ -2877,7 +2851,7 @@ static unsigned int DRW_engines_get_hash(void)
static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
{
BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
- rect->ymax - (3 + v++) * U.widget_unit, 0.0f,
+ rect->ymax - (3 + v) * U.widget_unit, 0.0f,
txt, size);
}
@@ -2968,66 +2942,32 @@ static void DRW_debug_gpu_stats(void)
UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- char time_to_txt[16];
- char pass_name[MAX_PASS_NAME + 16];
int v = BLI_listbase_count(&DST.enabled_engines) + 3;
- GLuint64 tot_time = 0;
-
- if (G.debug_value > 666) {
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
- GLuint64 engine_time = 0;
- DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
- int vsta = v;
- draw_stat(&rect, 0, v, engine->idname, sizeof(engine->idname));
- v++;
-
- for (int i = 0; i < engine->vedata_size->psl_len; ++i) {
- DRWPass *pass = data->psl->passes[i];
- if (pass != NULL && pass->wasdrawn) {
- GLuint64 time;
- glGetQueryObjectui64v(pass->timer_queries[pass->front_idx], GL_QUERY_RESULT, &time);
-
- sprintf(pass_name, " |--> %s", pass->name);
- draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
-
- sprintf(time_to_txt, "%.2fms", time / 1000000.0);
- engine_time += time;
- tot_time += time;
-
- draw_stat(&rect, 2, v++, time_to_txt, sizeof(time_to_txt));
-
- pass->wasdrawn = false;
- }
- }
- /* engine total time */
- sprintf(time_to_txt, "%.2fms", engine_time / 1000000.0);
- draw_stat(&rect, 2, vsta, time_to_txt, sizeof(time_to_txt));
- v++;
- }
-
- sprintf(pass_name, "Total GPU time %.2fms (%.1f fps)", tot_time / 1000000.0, 1000000000.0 / tot_time);
- draw_stat(&rect, 0, v++, pass_name, sizeof(pass_name));
- v++;
- }
+ char stat_string[32];
/* Memory Stats */
unsigned int tex_mem = GPU_texture_memory_usage_get();
unsigned int vbo_mem = GWN_vertbuf_get_memory_usage();
- sprintf(pass_name, "GPU Memory");
- draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
- sprintf(pass_name, "%.2fMB", (float)(tex_mem + vbo_mem) / 1000000.0);
- draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
- sprintf(pass_name, " |--> Textures");
- draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
- sprintf(pass_name, "%.2fMB", (float)tex_mem / 1000000.0);
- draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
- sprintf(pass_name, " |--> Meshes");
- draw_stat(&rect, 0, v, pass_name, sizeof(pass_name));
- sprintf(pass_name, "%.2fMB", (float)vbo_mem / 1000000.0);
- draw_stat(&rect, 1, v++, pass_name, sizeof(pass_name));
+ sprintf(stat_string, "GPU Memory");
+ draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (float)(tex_mem + vbo_mem) / 1000000.0);
+ draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, " |--> Textures");
+ draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (float)tex_mem / 1000000.0);
+ draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, " |--> Meshes");
+ draw_stat(&rect, 0, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (float)vbo_mem / 1000000.0);
+ draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string));
+
+ /* Pre offset for stats_draw */
+ rect.ymax -= (3 + ++v) * U.widget_unit;
+
+ /* Rendering Stats */
+ DRW_stats_draw(&rect);
}
@@ -3106,6 +3046,8 @@ void DRW_draw_render_loop_ex(
DRW_engines_cache_finish();
}
+ DRW_stats_begin();
+
/* Start Drawing */
DRW_state_reset();
DRW_engines_draw_background();
@@ -3136,6 +3078,8 @@ void DRW_draw_render_loop_ex(
DRW_draw_region_info();
}
+ DRW_stats_reset();
+
if (G.debug_value > 20) {
DRW_debug_cpu_stats();
DRW_debug_gpu_stats();
@@ -3555,6 +3499,7 @@ extern struct GPUTexture *globals_ramp; /* draw_common.c */
void DRW_engines_free(void)
{
DRW_shape_cache_free();
+ DRW_stats_free();
DrawEngineType *next;
for (DrawEngineType *type = DRW_engines.first; type; type = next) {
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
new file mode 100644
index 00000000000..bca9e50da99
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_manager_profiling.c
+ * \ingroup draw
+ */
+
+#include "BLI_rect.h"
+#include "BLI_string.h"
+
+#include "BKE_global.h"
+
+#include "BLF_api.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_glew.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "draw_manager_profiling.h"
+
+#define MAX_TIMER_NAME 32
+#define MAX_NESTED_TIMER 8
+#define CHUNK_SIZE 8
+#define GPU_TIMER_FALLOFF 0.1
+
+typedef struct DRWTimer {
+ GLuint query[2];
+ GLuint64 time_average;
+ char name[MAX_TIMER_NAME];
+ int lvl; /* Hierarchy level for nested timer. */
+ bool is_query; /* Does this timer actually perform queries or is it just a group. */
+} DRWTimer;
+
+static struct DRWTimerPool {
+ DRWTimer *timers;
+ int chunk_count; /* Number of chunk allocated. */
+ int timer_count; /* chunk_count * CHUNK_SIZE */
+ int timer_increment; /* Keep track of where we are in the stack. */
+ int end_increment; /* Keep track of bad usage. */
+ bool is_recording; /* Are we in the render loop? */
+ bool is_querying; /* Keep track of bad usage. */
+} DTP = {NULL};
+
+void DRW_stats_free(void)
+{
+ if (DTP.timers != NULL) {
+ for (int i = 0; i < DTP.timer_count; ++i) {
+ DRWTimer *timer = &DTP.timers[i];
+ glDeleteQueries(2, timer->query);
+ }
+ MEM_freeN(DTP.timers);
+ DTP.timers = NULL;
+ }
+}
+
+void DRW_stats_begin(void)
+{
+ if (G.debug_value > 20) {
+ DTP.is_recording = true;
+ }
+
+ if (DTP.is_recording && DTP.timers == NULL) {
+ DTP.chunk_count = 1;
+ DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timers = MEM_callocN(sizeof(DRWTimer) * DTP.timer_count, "DRWTimer stack");
+ }
+ else if(!DTP.is_recording && DTP.timers != NULL) {
+ DRW_stats_free();
+ }
+
+ DTP.is_querying = false;
+ DTP.timer_increment = 0;
+ DTP.end_increment = 0;
+}
+
+static DRWTimer *drw_stats_timer_get(void)
+{
+ if (UNLIKELY(DTP.timer_increment >= DTP.timer_count)) {
+ /* Resize the stack. */
+ DTP.chunk_count++;
+ DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timers = MEM_recallocN(DTP.timers, sizeof(DRWTimer) * DTP.timer_count);
+ }
+
+ return &DTP.timers[DTP.timer_increment++];
+}
+
+static void drw_stats_timer_start_ex(const char *name, const bool is_query)
+{
+ if (DTP.is_recording) {
+ DRWTimer *timer = drw_stats_timer_get();
+ BLI_strncpy(timer->name, name, MAX_TIMER_NAME);
+ timer->lvl = DTP.timer_increment - DTP.end_increment - 1;
+ timer->is_query = is_query;
+
+ /* Queries cannot be nested or interleaved. */
+ BLI_assert(!DTP.is_querying);
+ if (timer->is_query) {
+ if (timer->query[0] == 0) {
+ glGenQueries(1, timer->query);
+ }
+
+ /* Issue query for the next frame */
+ glBeginQuery(GL_TIME_ELAPSED, timer->query[0]);
+ DTP.is_querying = true;
+ }
+ }
+}
+
+/* Use this to group the queries. It does NOT keep track
+ * of the time, it only sum what the queries inside it. */
+void DRW_stats_group_start(const char *name)
+{
+ drw_stats_timer_start_ex(name, false);
+}
+
+void DRW_stats_group_end(void)
+{
+ if (DTP.is_recording) {
+ BLI_assert(!DTP.is_querying);
+ DTP.end_increment++;
+ }
+}
+
+/* NOTE: Only call this when no sub timer will be called. */
+void DRW_stats_query_start(const char *name)
+{
+ drw_stats_timer_start_ex(name, true);
+}
+
+void DRW_stats_query_end(void)
+{
+ if (DTP.is_recording) {
+ DTP.end_increment++;
+ BLI_assert(DTP.is_querying);
+ glEndQuery(GL_TIME_ELAPSED);
+ DTP.is_querying = false;
+ }
+}
+
+void DRW_stats_reset(void)
+{
+ BLI_assert((DTP.timer_increment - DTP.end_increment) <= 0 && "You forgot a DRW_stats_group/query_end somewhere!");
+ BLI_assert((DTP.timer_increment - DTP.end_increment) >= 0 && "You forgot a DRW_stats_group/query_start somewhere!");
+
+ if (DTP.is_recording) {
+ GLuint64 lvl_time[MAX_NESTED_TIMER] = {0};
+
+ /* Swap queries for the next frame and sum up each lvl time. */
+ for (int i = DTP.timer_increment - 1; i >= 0; --i) {
+ DRWTimer *timer = &DTP.timers[i];
+ SWAP(GLuint, timer->query[0], timer->query[1]);
+
+ BLI_assert(timer->lvl < MAX_NESTED_TIMER);
+
+ if (timer->is_query) {
+ GLuint64 time;
+ if (timer->query[0] != 0) {
+ glGetQueryObjectui64v(timer->query[0], GL_QUERY_RESULT, &time);
+ }
+ else {
+ time = 1000000000; /* 1ms default */
+ }
+
+ timer->time_average = timer->time_average * (1.0 - GPU_TIMER_FALLOFF) + time * GPU_TIMER_FALLOFF;
+ timer->time_average = MIN2(timer->time_average, 1000000000);
+ }
+ else {
+ timer->time_average = lvl_time[timer->lvl + 1];
+ lvl_time[timer->lvl + 1] = 0;
+ }
+
+ lvl_time[timer->lvl] += timer->time_average;
+ }
+
+ DTP.is_recording = false;
+ }
+}
+
+void DRW_stats_draw(rcti *rect)
+{
+ char stat_string[64];
+ int lvl_index[MAX_NESTED_TIMER];
+ int v = 0;
+
+ BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Stats");
+ BLF_draw_default_ascii(rect->xmin + 1 * U.widget_unit, rect->ymax - v++ * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+
+ for (int i = 0; i < DTP.timer_increment; ++i) {
+ double time_ms, time_percent;
+ DRWTimer *timer = &DTP.timers[i];
+ DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : NULL;
+
+ /* Only display a number of lvl at a time */
+ if ((G.debug_value - 21) < timer->lvl) continue;
+
+ BLI_assert(timer->lvl < MAX_NESTED_TIMER);
+ lvl_index[timer->lvl] = i;
+
+ time_ms = timer->time_average / 1000000.0;
+
+ if (timer_parent != NULL) {
+ time_percent = ((double)timer->time_average / (double)timer_parent->time_average) * 100.0;
+ }
+ else {
+ time_percent = 100.0;
+ }
+
+ /* avoid very long number */
+ time_ms = MIN2(time_ms, 999.0);
+ time_percent = MIN2(time_percent, 100.0);
+
+ BLI_snprintf(stat_string, sizeof(stat_string), "%.2fms", time_ms);
+ BLF_draw_default_ascii(rect->xmin + 1 * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ BLI_snprintf(stat_string, sizeof(stat_string), "%.0f", time_percent);
+ BLF_draw_default_ascii(rect->xmin + 4 * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ BLI_snprintf(stat_string, sizeof(stat_string), "%s", timer->name);
+ BLF_draw_default_ascii(rect->xmin + (6 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string));
+ v++;
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
new file mode 100644
index 00000000000..233cd3878d2
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_manager_profiling.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_MANAGER_PROFILING_H__
+#define __DRAW_MANAGER_PROFILING_H__
+
+struct rcti;
+
+void DRW_stats_free(void);
+void DRW_stats_begin(void);
+void DRW_stats_reset(void);
+
+void DRW_stats_group_start(const char *name);
+void DRW_stats_group_end(void);
+
+void DRW_stats_query_start(const char *name);
+void DRW_stats_query_end(void);
+
+void DRW_stats_draw(rcti *rect);
+
+#endif /* __DRAW_MANAGER_PROFILING_H__ */