cgv
Loading...
Searching...
No Matches
performance_monitor.cxx
1#include "performance_monitor.h"
2
3#include <cgv/gui/theme_info.h>
4#include <cgv/math/ftransform.h>
5#include <cgv_g2d/msdf_gl_font_renderer.h>
6
7namespace cgv {
8namespace overlay {
9
10performance_monitor::performance_monitor() {
11
12 set_name("Performance Monitor");
14
15 layout.padding = padding();
16 layout.total_size = ivec2(180, 80);
17
18 set_size(layout.total_size);
19
20 bar_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::rectangle);
21}
22
24
25 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
26
28
29 bar_renderer.destruct(ctx);
30 bars.destruct(ctx);
31 static_text_geometry.destruct(ctx);
32 dynamic_text_geometry.destruct(ctx);
33}
34
36
37 if(ptr.points_to(show_plot)) {
38 layout.total_size.y() = show_plot ? 80 : 45;
39 set_size(layout.total_size);
40 if(get_context())
41 create_static_texts(*get_context());
42 }
43
44 if(ptr.points_to_one_of(background_visible_, invert_color))
45 init_styles();
46
47 if(ptr.points_to(monitor.enabled)) {
48 if(monitor.enabled)
49 monitor.reset();
50 }
51}
52
54
55 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
56
57 register_shader("rectangle", cgv::g2d::shaders::rectangle);
58 register_shader("line", cgv::g2d::shaders::line);
59
60 bool success = canvas_overlay::init(ctx);
61
62 success &= bar_renderer.init(ctx);
63 success &= static_text_geometry.init(ctx);
64 success &= dynamic_text_geometry.init(ctx);
65
67 { 0.0f, rgb(0.5f, 1.0f, 0.5f) },
68 { 0.25f, rgb(0.0f, 0.9f, 0.0f) },
69 { 0.5f, rgb(0.8f, 0.9f, 0.0f) },
70 { 1.0f, rgb(0.9f, 0.0f, 0.0f) }
71 });
72
73 return success;
74}
75
77
78 if(ensure_layout(ctx)) {
79 layout.update(get_rectangle().size);
80 create_static_texts(ctx);
81 create_dynamic_texts(ctx);
82 }
83
84 bool enabled = monitor.enabled;
85 if(monitor.enabled_only_when_visible && !is_visible()) {
86 enabled = false;
87 }
88 if(enabled) {
89 if(show_plot)
90 update_plot();
91 update_dynamic_texts(ctx);
92 }
93}
94
95void performance_monitor::draw_content(cgv::render::context& ctx) {
96
97 begin_content(ctx);
98 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
99
100 if(show_plot) {
101 // draw plot border
102 content_canvas.enable_shader(ctx, "rectangle");
103 content_canvas.set_style(ctx, border_style);
104 content_canvas.draw_shape(ctx, layout.plot_rect.position - 1, layout.plot_rect.size + 2);
105
106 // draw plot bars
107 bar_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, bars, bar_style);
108
109 // draw line
110 const auto& r = layout.plot_rect;
111 ivec2 a(r.x() + 12, r.center().y());
112 ivec2 b = a;
113 b.x() = r.x1();
114
115 content_canvas.enable_shader(ctx, "line");
116 content_canvas.set_style(ctx, line_style);
117 content_canvas.draw_shape2(ctx, a, b);
118 content_canvas.disable_current_shader(ctx);
119 }
120
121 // draw text
122 font_renderer.render(ctx, content_canvas, static_text_geometry, text_style);
123 font_renderer.render(ctx, content_canvas, dynamic_text_geometry, text_style);
124
125 end_content(ctx);
126}
127
129
131
132 bool enabled = monitor.enabled;
133 if(monitor.enabled_only_when_visible && !is_visible())
134 enabled = false;
135
136 if(enabled) {
137 ++monitor.total_frame_count;
138 ++monitor.interval_frame_count;
139
140 double seconds_since_start = monitor.timer.get_elapsed_time();
141 monitor.delta_time = seconds_since_start - monitor.last_seconds_since_start;
142
143 monitor.running_time += monitor.delta_time;
144
145 monitor.last_seconds_since_start = seconds_since_start;
146
147 if(monitor.running_time >= monitor.interval) {
148 monitor.avg_fps = (double)monitor.interval_frame_count / monitor.running_time;
149 monitor.running_time = 0.0;
150 monitor.interval_frame_count = 0u;
151 }
152 }
153}
154
155void performance_monitor::set_invert_color(bool flag) {
156
157 invert_color = flag;
158 on_set(&invert_color);
159}
160
161void performance_monitor::enable_monitoring(bool enabled) {
162 monitor.enabled = enabled;
163 on_set(&monitor.enabled);
164}
165
166void performance_monitor::enable_monitoring_only_when_visible(bool enabled) {
167 monitor.enabled_only_when_visible = enabled;
168}
169
171
172 if(monitor.enabled_only_when_visible && is_visible()) {
173 if(monitor.enabled)
174 monitor.reset();
175 }
176}
177
179
180 add_member_control(this, "Enable", monitor.enabled, "check", "w=110", " ");
181 add_member_control(this, "Show Plot", show_plot, "check", "w=78");
182 add_member_control(this, "Measure Interval (s)", monitor.interval, "value_slider", "min=0.01;max=1;step=0.01;ticks=true");
183
184 add_member_control(this, "Background", background_visible_, "check", "w=100", " ");
185 add_member_control(this, "Invert Color", invert_color, "check", "w=88");
186}
187
188void performance_monitor::init_styles() {
189 auto& theme = cgv::gui::theme_info::instance();
190 rgb border_color = theme.text();
191
192 if(invert_color)
193 border_color = pow(rgb(1.0f) - pow(border_color, 2.2f), 1.0f / 2.2f);
194
195 // configure style for the border rectangle
196 border_style.fill_color = background_visible_ ? rgba(theme.text_background(), 1.0f) : rgba(0.0f);
197 border_style.border_color = rgba(border_color, 1.0);
198 border_style.border_width = 1.0f;
199 border_style.feather_width = 0.0f;
200 border_style.use_blending = true;
201
202 line_style.use_blending = true;
203 line_style.fill_color = rgba(border_color, invert_color ? 0.666f : 0.333f);
204 line_style.feather_width = 0.0f;
205 line_style.dash_length = 10.0f;
206
207 bar_style.use_fill_color = false;
208 bar_style.feather_width = 0.0f;
209
210 // configure text style
211 text_style.fill_color = border_color;
212 text_style.font_size = 12.0f;
213
214 tick_text_style = text_style;
215 tick_text_style.font_size = 10.0f;
216}
217
218void performance_monitor::create_static_texts(const cgv::render::context& ctx) {
219
220 static_text_geometry.clear();
221
222 std::vector<std::string> texts = {
223 "Frames per second:",
224 "Frametime (ms):"
225 };
226
227 const float line_spacing = 1.25f * text_style.font_size;
228 cgv::g2d::rect content_rect = static_cast<cgv::g2d::rect>(layout.content_rect);
229
230 vec3 caret_pos(content_rect.x(), content_rect.y1() - text_style.font_size, 0.0f);
231 static_text_geometry.positions.push_back(caret_pos);
232 caret_pos.y() -= line_spacing;
233 static_text_geometry.positions.push_back(caret_pos);
234
235 static_text_geometry.alignments = {
238
239 };
240
241 if(show_plot) {
242 texts.push_back("30");
243 texts.push_back("60");
244 texts.push_back("120");
245
246 cgv::g2d::rect plot_rect = static_cast<cgv::g2d::rect>(layout.plot_rect);
247
248 caret_pos = vec3(plot_rect.x(), plot_rect.y1(), 0.0f);
249 static_text_geometry.positions.push_back(caret_pos);
250 caret_pos.y() = plot_rect.center().y();
251 static_text_geometry.positions.push_back(caret_pos);
252 caret_pos.y() = plot_rect.y();
253 static_text_geometry.positions.push_back(caret_pos);
254
255 static_text_geometry.alignments.push_back(cgv::render::TA_TOP_LEFT),
256 static_text_geometry.alignments.push_back(cgv::render::TA_LEFT);
257 static_text_geometry.alignments.push_back(cgv::render::TA_BOTTOM_LEFT);
258 }
259
260 static_text_geometry.texts = texts;
261 static_text_geometry.create(ctx);
262}
263
264void performance_monitor::create_dynamic_texts(const cgv::render::context& ctx) {
265
266 dynamic_text_geometry.clear();
267
268 dynamic_text_geometry.texts = { "", "" };
269 dynamic_text_geometry.create(ctx);
270
271 const float line_spacing = 1.25f * text_style.font_size;
272 cgv::g2d::rect content_rect = static_cast<cgv::g2d::rect>(layout.content_rect);
273
274 vec3 caret_pos = vec3(content_rect.x1(), content_rect.y1() - text_style.font_size, 0.0f);
275 dynamic_text_geometry.positions.push_back(caret_pos);
276 caret_pos.y() -= line_spacing;
277 dynamic_text_geometry.positions.push_back(caret_pos);
278
279 dynamic_text_geometry.alignments = {
282 };
283}
284
285void performance_monitor::update_dynamic_texts(const cgv::render::context& ctx) {
286
287 std::vector<std::string> value_labels(2);
288
289 std::stringstream ss;
290 ss.precision(2);
291 ss << std::fixed;
292 ss << monitor.avg_fps;
293
294 value_labels[0] = ss.str();
295
296 ss.str(std::string());
297 if(monitor.avg_fps < 0.001f)
298 ss << "-";
299 else
300 ss << 1000.0 / monitor.avg_fps;
301
302 value_labels[1] = ss.str();
303
304 dynamic_text_geometry.texts = value_labels;
305 dynamic_text_geometry.create(ctx);
306 post_damage();
307}
308
309void performance_monitor::update_plot() {
310
311 ivec2 plot_size = layout.plot_rect.size;
312
313 float a = static_cast<float>(1000.0 * monitor.delta_time / 33.333333333);
314 float b = std::min(a, 1.0f);
315 float bar_height = plot_size.y() * b;
316 bar_height = std::max(bar_height, 1.0f);
317
318 rgb bar_color = a > 1.0f ? rgb(0.7f, 0.0f, 0.0f) : color_map.interpolate(b);
319
320 if(bars.render_count() < plot_size.x()) {
321 for(auto& position : bars.position)
322 position.x() -= 1.0f;
323
324 int x = layout.plot_rect.x1() - 1;
325 x = std::max(x, 0);
326 float bar_x = static_cast<float>(x);
327 bars.add(vec2(bar_x, static_cast<float>(layout.plot_rect.y())), vec2(1.0f, bar_height), bar_color);
328
329 } else {
330 for(size_t i = 0; i < bars.position.size() - 1; ++i) {
331 bars.size[i].y() = bars.size[i + 1].y();
332 bars.color[i] = bars.color[i + 1];
333 }
334
335 bars.size.back() = vec2(1.0f, bar_height);
336 bars.color.back() = bar_color;
337 }
338
339 bars.set_out_of_date();
340 post_damage();
341}
342
343} // namespace overlay
344} // namespace cgv
void set_name(const std::string &_name)
set a new parent node
Definition named.cxx:13
This class provides methods to test if a stored pointer points to addresses of given variables or ins...
bool points_to_one_of(const T &ref, const Ts &... refs) const
Return true if the stored pointer points to one of the given objects.
bool points_to(const T &ref) const
Return true if the stored pointer points to the given object.
data::ref_ptr< control< T > > add_member_control(cgv::base::base *base_ptr, const std::string &label, T &value, const std::string &gui_type="", const std::string &options="", const std::string &align="\n")
add control with callback to cgv::base::on_set method on cgv::gui::control::value_change
Definition provider.h:137
T & y()
return second component
Definition fvec.h:140
T & x()
return first component
Definition fvec.h:136
static continuous_color_scheme linear(const std::vector< cgv::rgb > &colors, ColorSchemeType type=ColorSchemeType::kUndefined)
Create a continuous_color_scheme using uniform linear interpolation of the given colors.
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
virtual void on_set(void *member_ptr) override
default implementation of that calls handle_member_change and afterwards upates the member in the gui...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
Definition overlay.cxx:111
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
Definition overlay.h:95
gui_options_t gui_options
options for the GUI creation of this overlay (must be set before GUI creation)
Definition overlay.h:59
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void after_finish(cgv::render::context &ctx) override
draw the content of the canvas overlay
bool enabled
whether measuring is enabled
void on_visibility_change() override
called when the overlay visibility is changed through the default gui
void init_frame(cgv::render::context &ctx) override
this method is called in one pass over all drawables before the draw method
void create_gui_impl() override
virtual method to implement the derived class gui creation
void handle_member_change(cgv::data::informed_ptr ptr) override
implement to handle member changes
struct cgv::overlay::performance_monitor::@19 monitor
measuring state fields
bool background_visible_
whether the background is visible (true by default)
base class for all drawables, which is independent of the used rendering API.
Definition context.h:668
context * get_context() const
access the current context. The context will be available latestly in the init method but not in the ...
Definition drawable.cxx:37
virtual void after_finish(context &)
this method is called in one pass over all drawables after finish frame
Definition drawable.cxx:125
bool is_visible() const
check whether the drawable is visible
Definition drawable.cxx:31
@ TA_BOTTOM_RIGHT
bottom right corner of text bounds
Definition context.h:338
@ TA_BOTTOM_LEFT
bottom left corner of text bounds
Definition context.h:337
@ TA_TOP_LEFT
top left corner of text bounds
Definition context.h:335
@ TA_LEFT
center of left edge of text bounds
Definition context.h:331
this header is dependency free
Definition print.h:11
cgv::media::color< float, cgv::media::RGB, cgv::media::OPACITY > rgba
declare rgba color type with 32 bit components
Definition color.h:898
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
Definition color.h:896
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
Definition fvec.h:708
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
Definition fvec.h:681
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors
Definition fvec.h:683
bool allow_stretch
whether to show the stretch options (show_layout_options must be enabled)
Definition overlay.h:54