Unravel Engine C++ Reference
Loading...
Searching...
No Matches
statistics_panel.cpp
Go to the documentation of this file.
1#include "statistics_panel.h"
2#include "imgui_widgets/utils.h"
3#include "statistics_utils.h"
4
6#include <graphics/graphics.h>
7#include <math/math.h>
8
9#include <algorithm>
10#include <array>
11#include <numeric>
12
13namespace unravel
14{
15
16// Constants
17namespace
18{
19 constexpr float plot_height = 50.0f;
20 constexpr float max_frame_time_ms = 200.0f;
21 constexpr float max_passes = 200.0f;
22 constexpr float profiler_scale = 3.0f;
23 constexpr float profiler_max_width = 30.0f;
24 constexpr float resource_bar_width = 90.0f;
25 constexpr float megabyte_divisor = 1024.0f * 1024.0f;
26
27 // Colors for profiler bars
28 constexpr ImVec4 cpu_color{0.2f, 0.8f, 0.2f, 1.0f}; // More professional green
29 constexpr ImVec4 gpu_color{0.2f, 0.6f, 1.0f, 1.0f}; // More professional blue
30 constexpr ImVec4 warning_color{1.0f, 0.7f, 0.0f, 1.0f}; // Warning orange
31 constexpr ImVec4 error_color{1.0f, 0.3f, 0.3f, 1.0f}; // Error red
32
33 // Static sample data instances
34 statistics_utils::sample_data frame_time_samples;
35 statistics_utils::sample_data graphics_passes_samples;
36 statistics_utils::sample_data gpu_memory_samples;
37 statistics_utils::sample_data render_target_memory_samples;
38 statistics_utils::sample_data texture_memory_samples;
39}
40
42{
43 // No specific initialization needed currently
44}
45
47{
48 // No specific cleanup needed currently
49}
50
52{
53 // No per-frame update logic needed currently
54}
55
57{
58 // No per-frame render logic needed currently
59}
60
62{
63 if(ImGui::Begin(name, nullptr, ImGuiWindowFlags_MenuBar))
64 {
65 draw_menubar(ctx);
66 draw_statistics_content();
67 }
68 ImGui::End();
69}
70
71auto statistics_panel::draw_menubar(rtti::context& ctx) -> void
72{
73 if(ImGui::BeginMenuBar())
74 {
75 if(ImGui::BeginMenu("View " ICON_MDI_ARROW_DOWN_BOLD))
76 {
77 ImGui::Checkbox("Show Editor Stats", &show_editor_stats_);
78 ImGui::SetItemTooltip("Show editor/UI related draw calls and triangles\n(Focus on scene stats when disabled)");
79 ImGui::EndMenu();
80 }
81 ImGui::EndMenuBar();
82 }
83}
84
85auto statistics_panel::draw_statistics_content() -> void
86{
87 const auto& io = ImGui::GetIO();
88 const auto area = ImGui::GetContentRegionAvail();
89 const float overlay_width = area.x;
90
91 // Update sample data with current frame statistics
92 update_sample_data();
93
94 // Draw main statistics sections
95 draw_frame_statistics(overlay_width);
96 draw_profiler_section();
97 draw_memory_info_section(overlay_width);
98 draw_resources_section();
99}
100
101auto statistics_panel::draw_frame_statistics(float overlay_width) -> void
102{
103 auto stats = gfx::get_stats();
104 const auto& io = ImGui::GetIO();
105
106 const double to_cpu_ms = 1000.0 / static_cast<double>(stats->cpuTimerFreq);
107 const double to_gpu_ms = 1000.0 / static_cast<double>(stats->gpuTimerFreq);
108
109 // Performance Overview Section
110 if(ImGui::CollapsingHeader(ICON_MDI_CHART_LINE "\tPerformance Overview", ImGuiTreeNodeFlags_DefaultOpen))
111 {
113
114 // Frame time statistics with color coding
115 const float avg_frame_time = frame_time_samples.get_average();
116 const float fps = 1000.0f / avg_frame_time;
117
118 // Color code based on performance
119 ImVec4 fps_color = cpu_color; // Green for good performance
120 if(fps < 30.0f)
121 {
122 fps_color = error_color; // Red for poor
123 }
124 else if(fps < 55.0f)
125 {
126 fps_color = warning_color; // Orange for moderate
127 }
128
129 // Performance summary with better layout
130 ImGui::BeginColumns("PerformanceColumns", 2, ImGuiOldColumnFlags_NoResize);
131 ImGui::SetColumnWidth(0, overlay_width * 0.5f);
132
133 ImGui::Text("Frame Time:");
134 ImGui::Text(" Average: %.3f ms", avg_frame_time);
135 ImGui::Text(" Min/Max: %.3f / %.3f ms", frame_time_samples.get_min(), frame_time_samples.get_max());
136
137 ImGui::NextColumn();
138
139 ImGui::TextColored(fps_color, "FPS: %.1f", fps);
140 if(fps < 55.0f)
141 {
142 ImGui::SameLine();
143 ImGui::TextColored(warning_color, fps < 30.0f ? " (Poor)" : " (Low)");
144 }
145
146 // GPU Memory usage with color coding
147 if(stats->gpuMemoryUsed > 0)
148 {
149 std::array<char, 64> gpu_used_str;
150 bx::prettify(gpu_used_str.data(), gpu_used_str.size(), stats->gpuMemoryUsed);
151
152 ImGui::Text("GPU Memory:");
153
154 if(stats->gpuMemoryMax > 0)
155 {
156 // Full memory info with percentage when max is available
157 const float gpu_usage_percentage = (static_cast<float>(stats->gpuMemoryUsed) / static_cast<float>(stats->gpuMemoryMax)) * 100.0f;
158
159 // Color code based on GPU memory usage (only for percentage)
160 ImVec4 gpu_memory_color = cpu_color; // Green for low usage
161 if(gpu_usage_percentage > 80.0f)
162 {
163 gpu_memory_color = error_color; // Red for high
164 }
165 else if(gpu_usage_percentage > 60.0f)
166 {
167 gpu_memory_color = warning_color; // Orange for medium
168 }
169
170 std::array<char, 64> gpu_max_str;
171 bx::prettify(gpu_max_str.data(), gpu_max_str.size(), stats->gpuMemoryMax);
172
173 ImGui::Text("%s / %s", gpu_used_str.data(), gpu_max_str.data());
174 ImGui::SameLine();
175 ImGui::TextColored(gpu_memory_color, "(%.1f%%)", gpu_usage_percentage);
176 }
177 else
178 {
179 // Only current usage when max is not available
180 ImGui::Text("%s used", gpu_used_str.data());
181 ImGui::SameLine();
182 ImGui::TextColored(warning_color, "(max unknown)");
183 }
184 }
185 else
186 {
187 ImGui::Text("GPU Memory:");
188 ImGui::TextColored(warning_color, "No data available");
189 }
190
191 ImGui::EndColumns();
192
193 // Frame time plot with improved overlay
194 std::array<char, 256> frame_text_overlay;
195 bx::snprintf(frame_text_overlay.data(),
196 frame_text_overlay.size(),
197 "Performance: %.1f FPS (%.3f ms avg)\nRange: %.3f - %.3f ms",
198 fps, avg_frame_time,
199 frame_time_samples.get_min(),
200 frame_time_samples.get_max());
201
202 ImGui::SetNextWindowViewportToCurrent();
203 ImGui::PlotLines("##FrameTime",
204 frame_time_samples.get_values(),
206 frame_time_samples.get_offset(),
207 frame_text_overlay.data(),
208 0.0f,
209 max_frame_time_ms,
210 ImVec2(overlay_width, plot_height));
211
212 ImGui::Separator();
213
214 // CPU/GPU timing with better formatting
215 const auto submit_cpu_ms = static_cast<double>(stats->cpuTimeEnd - stats->cpuTimeBegin) * to_cpu_ms;
216 const auto submit_gpu_ms = static_cast<double>(stats->gpuTimeEnd - stats->gpuTimeBegin) * to_gpu_ms;
217
218 ImGui::BeginColumns("TimingColumns", 4, ImGuiOldColumnFlags_NoResize);
219 ImGui::SetColumnWidth(0, overlay_width * 0.25f);
220 ImGui::SetColumnWidth(1, overlay_width * 0.25f);
221 ImGui::SetColumnWidth(2, overlay_width * 0.25f);
222
223 ImGui::TextColored(cpu_color, "CPU Submit");
224 ImGui::Text("%.3f ms", submit_cpu_ms);
225
226 ImGui::NextColumn();
227 ImGui::TextColored(gpu_color, "GPU Submit");
228 ImGui::Text("%.3f ms", submit_gpu_ms);
229
230 ImGui::NextColumn();
231 ImGui::Text("GPU Latency");
232 ImGui::Text("%d frames", stats->maxGpuLatency);
233
234 ImGui::NextColumn();
235 ImGui::Text("Draw Calls");
236
237 std::uint32_t scene_calls = 0, editor_calls = 0, total_calls = 0;
238 get_draw_call_breakdown(stats, scene_calls, editor_calls, total_calls);
239
240 if(show_editor_stats_)
241 {
242 ImGui::Text("%u total", total_calls);
243 }
244 else
245 {
246 ImGui::Text("%u scene", scene_calls);
247 }
248
249 ImGui::EndColumns();
250
251 ImGui::PopFont();
252 }
253
254 // Rendering Statistics Section
255 if(ImGui::CollapsingHeader(ICON_MDI_CUBE_OUTLINE "\tRendering Statistics", ImGuiTreeNodeFlags_DefaultOpen))
256 {
258
259 // Render passes at the top
260 ImGui::Text("Render Passes: %u", gfx::render_pass::get_last_frame_max_pass_id());
261 ImGui::Separator();
262
263 // Draw call counts
264 draw_call_counts(stats, io);
265
266 ImGui::Separator();
267
268 // Primitive counts
269 draw_primitive_counts(stats, io);
270
271
272 ImGui::PopFont();
273 }
274}
275
276auto statistics_panel::draw_profiler_section() -> void
277{
278 if(!ImGui::CollapsingHeader(ICON_MDI_CLOCK_OUTLINE "\tProfiler"))
279 {
280 return;
281 }
282
284
285 // CPU Profiler - always shown
286 ImGui::Text("CPU Profiler:");
287 draw_app_profiler_data();
288
289 ImGui::Separator();
290
291 // GPU Profiler controls
292 ImGui::AlignTextToFramePadding();
293 ImGui::Text("GPU Profiler:");
294 ImGui::SameLine();
295
296 if(ImGui::Checkbox("Enable##GPUProfiler", &enable_gpu_profiler_))
297 {
298 if(enable_gpu_profiler_)
299 {
300 gfx::set_debug(BGFX_DEBUG_PROFILER);
301 }
302 else
303 {
304 gfx::set_debug(BGFX_DEBUG_NONE);
305 }
306 }
307
308 // GPU Profiler data - conditionally shown
309 if(enable_gpu_profiler_)
310 {
311 auto stats = gfx::get_stats();
312
313 if(stats->numViews == 0)
314 {
315 ImGui::TextColored(warning_color, "No GPU profiling data available.");
316 ImGui::Text("Profiler may be initializing...");
317 }
318 else
319 {
320 ImGui::Text("GPU Timing (per view/encoder):");
321 draw_profiler_bars(stats);
322 }
323 }
324 else
325 {
326 ImGui::TextColored(warning_color, "GPU profiler is disabled.");
327 ImGui::Text("Enable to see detailed GPU timing information.");
328 }
329
330 ImGui::PopFont();
331}
332
333auto statistics_panel::draw_memory_info_section(float overlay_width) -> void
334{
335 if(!ImGui::CollapsingHeader(ICON_MDI_INFORMATION "\tMemory Usage"))
336 {
337 return;
338 }
339
341
342 auto stats = gfx::get_stats();
343 auto gpu_memory_max = stats->gpuMemoryMax;
344
345 // GPU memory section
346 if(stats->gpuMemoryUsed > 0)
347 {
348 draw_gpu_memory_section(stats, gpu_memory_max, overlay_width);
349 }
350 else
351 {
352 ImGui::TextColored(warning_color, "No GPU memory usage data available");
353 }
354
355 // Render target memory section
356 draw_render_target_memory_section(stats, gpu_memory_max, overlay_width);
357
358 // Texture memory section
359 draw_texture_memory_section(stats, gpu_memory_max, overlay_width);
360
361 ImGui::Unindent();
362 ImGui::PopFont();
363}
364
365auto statistics_panel::draw_resources_section() -> void
366{
367 if(!ImGui::CollapsingHeader(ICON_MDI_PUZZLE "\tGPU Resources"))
368 {
369 return;
370 }
371
372 const auto caps = gfx::get_caps();
373 const auto stats = gfx::get_stats();
374 const float item_height = ImGui::GetTextLineHeightWithSpacing();
375
377
378 ImGui::Text("Resource Usage (Current / Maximum):");
379 ImGui::Separator();
380
381 // Group resources by category for better organization
382 ImGui::Text("Buffers:");
383 ImGui::Indent();
384
385 using namespace statistics_utils;
386
387 draw_resource_bar("DIB", "Dynamic Index Buffers",
388 stats->numDynamicIndexBuffers, caps->limits.maxDynamicIndexBuffers,
389 resource_bar_width, item_height);
390
391 draw_resource_bar("DVB", "Dynamic Vertex Buffers",
392 stats->numDynamicVertexBuffers, caps->limits.maxDynamicVertexBuffers,
393 resource_bar_width, item_height);
394
395 draw_resource_bar(" IB", "Index Buffers",
396 stats->numIndexBuffers, caps->limits.maxIndexBuffers,
397 resource_bar_width, item_height);
398
399 draw_resource_bar(" VB", "Vertex Buffers",
400 stats->numVertexBuffers, caps->limits.maxVertexBuffers,
401 resource_bar_width, item_height);
402
403 ImGui::Unindent();
404 ImGui::Separator();
405
406 ImGui::Text("Shading:");
407 ImGui::Indent();
408
409 draw_resource_bar(" P", "Shader Programs",
410 stats->numPrograms, caps->limits.maxPrograms,
411 resource_bar_width, item_height);
412
413 draw_resource_bar(" S", "Shaders",
414 stats->numShaders, caps->limits.maxShaders,
415 resource_bar_width, item_height);
416
417 draw_resource_bar(" U", "Uniforms",
418 stats->numUniforms, caps->limits.maxUniforms,
419 resource_bar_width, item_height);
420
421 ImGui::Unindent();
422 ImGui::Separator();
423
424 ImGui::Text("Rendering:");
425 ImGui::Indent();
426
427 draw_resource_bar(" T", "Textures",
428 stats->numTextures, caps->limits.maxTextures,
429 resource_bar_width, item_height);
430
431 draw_resource_bar(" FB", "Frame Buffers",
432 stats->numFrameBuffers, caps->limits.maxFrameBuffers,
433 resource_bar_width, item_height);
434
435 draw_resource_bar(" VD", "Vertex Layouts",
436 stats->numVertexLayouts, caps->limits.maxVertexLayouts,
437 resource_bar_width, item_height);
438
439 draw_resource_bar(" OQ", "Occlusion Queries",
440 stats->numOcclusionQueries, caps->limits.maxOcclusionQueries,
441 resource_bar_width, item_height);
442
443 ImGui::Unindent();
444 ImGui::PopFont();
445}
446
447// Private helper methods
448
449auto statistics_panel::update_sample_data() -> void
450{
451 auto stats = gfx::get_stats();
452 const double to_cpu_ms = 1000.0 / static_cast<double>(stats->cpuTimerFreq);
453 const double frame_ms = static_cast<double>(stats->cpuTimeFrame) * to_cpu_ms;
454
455 frame_time_samples.push_sample(static_cast<float>(frame_ms));
456 graphics_passes_samples.push_sample(static_cast<float>(gfx::render_pass::get_last_frame_max_pass_id()));
457 gpu_memory_samples.push_sample(static_cast<float>(stats->gpuMemoryUsed) / megabyte_divisor);
458 render_target_memory_samples.push_sample(static_cast<float>(stats->rtMemoryUsed) / megabyte_divisor);
459 texture_memory_samples.push_sample(static_cast<float>(stats->textureMemoryUsed) / megabyte_divisor);
460}
461
462auto statistics_panel::get_draw_call_breakdown(const gfx::stats* stats, std::uint32_t& scene_calls, std::uint32_t& editor_calls, std::uint32_t& total_calls) -> void
463{
464 const ImGuiIO& io = ImGui::GetIO();
465 total_calls = stats->numDraw;
466 editor_calls = ImGui::GetDrawCalls();
467 editor_calls = std::min(editor_calls, total_calls);
468 scene_calls = total_calls - editor_calls;
469}
470
471auto statistics_panel::draw_primitive_counts(const gfx::stats* stats, const ImGuiIO& io) -> void
472{
473 const std::uint32_t total_primitives = std::accumulate(std::begin(stats->numPrims), std::end(stats->numPrims), 0u);
474 std::uint32_t ui_primitives = io.MetricsRenderIndices / 3;
475 ui_primitives = std::min(ui_primitives, total_primitives);
476 const auto scene_primitives = total_primitives - ui_primitives;
477
478 ImGui::Text("Triangle Counts:");
479 ImGui::Indent();
480
481 if(show_editor_stats_)
482 {
483 // Show detailed breakdown with editor stats
484 ImGui::BeginColumns("PrimitiveColumns", 2, ImGuiOldColumnFlags_NoResize);
485 ImGui::SetColumnWidth(0, 120.0f);
486
487 ImGui::Text("Scene:");
488 ImGui::NextColumn();
489 ImGui::TextColored(cpu_color, "%u triangles", scene_primitives);
490 ImGui::NextColumn();
491
492 ImGui::Text("Editor:");
493 ImGui::NextColumn();
494 ImGui::TextColored(gpu_color, "%u triangles", ui_primitives);
495 ImGui::NextColumn();
496
497 ImGui::Text("Total:");
498 ImGui::NextColumn();
499 ImGui::Text("%u triangles", total_primitives);
500
501 ImGui::EndColumns();
502 }
503 else
504 {
505 // Show only scene stats (main focus)
506 ImGui::TextColored(cpu_color, "Scene: %u triangles", scene_primitives);
507 }
508
509 ImGui::Unindent();
510}
511
512auto statistics_panel::draw_call_counts(const gfx::stats* stats, const ImGuiIO& io) -> void
513{
514 std::uint32_t scene_calls = 0, editor_calls = 0, total_calls = 0;
515 get_draw_call_breakdown(stats, scene_calls, editor_calls, total_calls);
516
517 ImGui::Text("GPU Commands:");
518 ImGui::Indent();
519
520 if(show_editor_stats_)
521 {
522 // Show detailed breakdown with editor stats
523 ImGui::BeginColumns("CallCountColumns", 2, ImGuiOldColumnFlags_NoResize);
524 ImGui::SetColumnWidth(0, 120.0f);
525
526 // Draw calls section
527 ImGui::Text("Draw Calls:");
528 ImGui::NextColumn();
529 ImGui::Text("%u total", total_calls);
530 ImGui::NextColumn();
531
532 ImGui::Text(" Scene:");
533 ImGui::NextColumn();
534 ImGui::TextColored(cpu_color, "%u calls", scene_calls);
535 ImGui::NextColumn();
536
537 ImGui::Text(" Editor:");
538 ImGui::NextColumn();
539 ImGui::TextColored(gpu_color, "%u calls", editor_calls);
540 ImGui::NextColumn();
541
542 // Other command types
543 ImGui::Text("Compute:");
544 ImGui::NextColumn();
545 ImGui::Text("%u calls", stats->numCompute);
546 ImGui::NextColumn();
547
548 ImGui::Text("Blit:");
549 ImGui::NextColumn();
550 ImGui::Text("%u calls", stats->numBlit);
551
552 ImGui::EndColumns();
553 }
554 else
555 {
556 // Show only scene-focused stats
557 ImGui::TextColored(cpu_color, "Scene Draw Calls: %u", scene_calls);
558
559 // Still show compute and blit as they're typically scene-related
560 if(stats->numCompute > 0 || stats->numBlit > 0)
561 {
562 ImGui::BeginColumns("SceneCallColumns", 2, ImGuiOldColumnFlags_NoResize);
563 ImGui::SetColumnWidth(0, 120.0f);
564
565 if(stats->numCompute > 0)
566 {
567 ImGui::Text("Compute:");
568 ImGui::NextColumn();
569 ImGui::Text("%u calls", stats->numCompute);
570 ImGui::NextColumn();
571 }
572
573 if(stats->numBlit > 0)
574 {
575 ImGui::Text("Blit:");
576 ImGui::NextColumn();
577 ImGui::Text("%u calls", stats->numBlit);
578 ImGui::NextColumn();
579 }
580
581 ImGui::EndColumns();
582 }
583 }
584
585 ImGui::Unindent();
586}
587
588auto statistics_panel::draw_profiler_bars(const gfx::stats* stats) -> void
589{
590 const float item_height = ImGui::GetTextLineHeightWithSpacing();
591 const float item_height_with_spacing = ImGui::GetFrameHeightWithSpacing();
592 const double to_cpu_ms = 1000.0 / static_cast<double>(stats->cpuTimerFreq);
593 const double to_gpu_ms = 1000.0 / static_cast<double>(stats->gpuTimerFreq);
594
595 // Draw encoder stats
596 draw_encoder_stats(stats, item_height, item_height_with_spacing, to_cpu_ms);
597
598 ImGui::Separator();
599
600 // Draw view stats
601 draw_view_stats(stats, item_height, item_height_with_spacing, to_cpu_ms, to_gpu_ms);
602}
603
604auto statistics_panel::draw_encoder_stats(const gfx::stats* stats, float item_height, float item_height_with_spacing, double to_cpu_ms) -> void
605{
606 if(ImGui::BeginListBox("Encoders", ImVec2(ImGui::GetWindowWidth(), stats->numEncoders * item_height_with_spacing)))
607 {
608 ImGuiListClipper clipper;
609 clipper.Begin(stats->numEncoders, item_height);
610
611 while(clipper.Step())
612 {
613 for(int32_t pos = clipper.DisplayStart; pos < clipper.DisplayEnd; ++pos)
614 {
615 const bgfx::EncoderStats& encoder_stats = stats->encoderStats[pos];
616 ImGui::PushID(pos);
617 ImGui::Text("%3d", pos);
618 ImGui::SameLine(64.0f);
619
620 const float max_width = profiler_max_width * profiler_scale;
621 const float cpu_ms = static_cast<float>((encoder_stats.cpuTimeEnd - encoder_stats.cpuTimeBegin) * to_cpu_ms);
622 const float cpu_width = bx::clamp(cpu_ms * profiler_scale, 1.0f, max_width);
623
624 if(statistics_utils::draw_progress_bar(cpu_width, max_width, item_height, cpu_color))
625 {
626 ImGui::SetItemTooltipEx("Encoder %d, CPU: %f [ms]", pos, cpu_ms);
627 }
628
629 ImGui::PopID();
630 }
631 }
632 ImGui::EndListBox();
633 }
634}
635
636auto statistics_panel::draw_view_stats(const gfx::stats* stats, float item_height, float item_height_with_spacing, double to_cpu_ms, double to_gpu_ms) -> void
637{
638 if(ImGui::BeginListBox("Views", ImVec2(ImGui::GetWindowWidth(), stats->numViews * item_height_with_spacing)))
639 {
640 ImGuiListClipper clipper;
641 clipper.Begin(stats->numViews, item_height);
642
643 while(clipper.Step())
644 {
645 for(int32_t pos = clipper.DisplayStart; pos < clipper.DisplayEnd; ++pos)
646 {
647 const bgfx::ViewStats& view_stats = stats->viewStats[pos];
648 ImGui::PushID(view_stats.view);
649 ImGui::Text("%3d %3d %s", pos, view_stats.view, view_stats.name);
650
651 const float max_width = profiler_max_width * profiler_scale;
652 const float cpu_time_elapsed = static_cast<float>((view_stats.cpuTimeEnd - view_stats.cpuTimeBegin) * to_cpu_ms);
653 const float gpu_time_elapsed = static_cast<float>((view_stats.gpuTimeEnd - view_stats.gpuTimeBegin) * to_gpu_ms);
654 const float cpu_width = bx::clamp(cpu_time_elapsed * profiler_scale, 1.0f, max_width);
655 const float gpu_width = bx::clamp(gpu_time_elapsed * profiler_scale, 1.0f, max_width);
656
657 ImGui::SameLine(64.0f);
658
659 ImGui::PushID("cpu");
660 if(statistics_utils::draw_progress_bar(cpu_width, max_width, item_height, cpu_color))
661 {
662 ImGui::SetItemTooltipEx("View %d \"%s\", CPU: %f [ms]", pos, view_stats.name, cpu_time_elapsed);
663 }
664 ImGui::PopID();
665
666 ImGui::SameLine();
667
668 ImGui::PushID("gpu");
669 if(statistics_utils::draw_progress_bar(gpu_width, max_width, item_height, gpu_color))
670 {
671 ImGui::SetItemTooltipEx("View: %d \"%s\", GPU: %f [ms]", pos, view_stats.name, gpu_time_elapsed);
672 }
673 ImGui::PopID();
674
675 ImGui::PopID();
676 }
677 }
678 ImGui::EndListBox();
679 }
680}
681
682auto statistics_panel::draw_app_profiler_data() -> void
683{
684 auto profiler = get_app_profiler();
685 const auto& data = profiler->get_per_frame_data_read();
686
687 for(const auto& [name, per_frame_data] : data)
688 {
689 ImGui::TextUnformatted(
690 fmt::format("{:>7.3f}ms [{:^5}] - {}",
691 per_frame_data.time,
692 per_frame_data.samples,
693 fmt::string_view(name.data(), name.size())).c_str());
694 }
695}
696
697auto statistics_panel::draw_gpu_memory_section(const gfx::stats* stats, int64_t& gpu_memory_max, float overlay_width) -> void
698{
699 gpu_memory_max = std::max(stats->gpuMemoryUsed, stats->gpuMemoryMax);
700
701 std::array<char, 64> str_max;
702 bx::prettify(str_max.data(), str_max.size(), static_cast<uint64_t>(gpu_memory_max));
703
704 std::array<char, 64> str_used;
705 bx::prettify(str_used.data(), str_used.size(), stats->gpuMemoryUsed);
706
707 const float usage_percentage = gpu_memory_max > 0 ?
708 (static_cast<float>(stats->gpuMemoryUsed) / static_cast<float>(gpu_memory_max)) * 100.0f : 0.0f;
709
710 // Color code based on usage
711 ImVec4 usage_color = cpu_color; // Green for low usage
712 if(usage_percentage > 80.0f)
713 {
714 usage_color = error_color; // Red for high
715 }
716 else if(usage_percentage > 60.0f)
717 {
718 usage_color = warning_color; // Orange for medium
719 }
720
721 ImGui::Separator();
722 ImGui::Text("General GPU Memory:");
723 ImGui::Indent();
724 ImGui::Text("Usage: %s / %s", str_used.data(), str_max.data());
725 ImGui::SameLine();
726 ImGui::TextColored(usage_color, "(%.1f%%)", usage_percentage);
727
728 ImGui::SetNextWindowViewportToCurrent();
729 ImGui::PlotLines("##GPUMemory",
730 gpu_memory_samples.get_values(),
732 gpu_memory_samples.get_offset(),
733 "GPU Memory Usage Over Time",
734 0.0f,
735 static_cast<float>(gpu_memory_max),
736 ImVec2(overlay_width, plot_height));
737 ImGui::Unindent();
738}
739
740auto statistics_panel::draw_render_target_memory_section(const gfx::stats* stats, int64_t& gpu_memory_max, float overlay_width) -> void
741{
742 gpu_memory_max = std::max(stats->rtMemoryUsed, gpu_memory_max);
743
744 std::array<char, 64> str_max;
745 bx::prettify(str_max.data(), str_max.size(), static_cast<uint64_t>(gpu_memory_max));
746
747 std::array<char, 64> str_used;
748 bx::prettify(str_used.data(), str_used.size(), stats->rtMemoryUsed);
749
750 const float usage_percentage = gpu_memory_max > 0 ?
751 (static_cast<float>(stats->rtMemoryUsed) / static_cast<float>(gpu_memory_max)) * 100.0f : 0.0f;
752
753 // Color code based on usage
754 ImVec4 usage_color = cpu_color; // Green for low usage
755 if(usage_percentage > 80.0f)
756 {
757 usage_color = error_color; // Red for high
758 }
759 else if(usage_percentage > 60.0f)
760 {
761 usage_color = warning_color; // Orange for medium
762 }
763
764 ImGui::Separator();
765 ImGui::Text("Render Target Memory:");
766 ImGui::Indent();
767 ImGui::Text("Usage: %s / %s", str_used.data(), str_max.data());
768 ImGui::SameLine();
769 ImGui::TextColored(usage_color, "(%.1f%%)", usage_percentage);
770
771 ImGui::SetNextWindowViewportToCurrent();
772 ImGui::PlotLines("##RenderTargetMemory",
773 render_target_memory_samples.get_values(),
775 render_target_memory_samples.get_offset(),
776 "Render Target Memory Usage Over Time",
777 0.0f,
778 static_cast<float>(gpu_memory_max),
779 ImVec2(overlay_width, plot_height));
780 ImGui::Unindent();
781}
782
783auto statistics_panel::draw_texture_memory_section(const gfx::stats* stats, int64_t& gpu_memory_max, float overlay_width) -> void
784{
785 gpu_memory_max = std::max(stats->textureMemoryUsed, gpu_memory_max);
786
787 std::array<char, 64> str_max;
788 bx::prettify(str_max.data(), str_max.size(), static_cast<uint64_t>(gpu_memory_max));
789
790 std::array<char, 64> str_used;
791 bx::prettify(str_used.data(), str_used.size(), stats->textureMemoryUsed);
792
793 const float usage_percentage = gpu_memory_max > 0 ?
794 (static_cast<float>(stats->textureMemoryUsed) / static_cast<float>(gpu_memory_max)) * 100.0f : 0.0f;
795
796 // Color code based on usage
797 ImVec4 usage_color = cpu_color; // Green for low usage
798 if(usage_percentage > 80.0f)
799 {
800 usage_color = error_color; // Red for high
801 }
802 else if(usage_percentage > 60.0f)
803 {
804 usage_color = warning_color; // Orange for medium
805 }
806
807 ImGui::Separator();
808 ImGui::Text("Texture Memory:");
809 ImGui::Indent();
810 ImGui::Text("Usage: %s / %s", str_used.data(), str_max.data());
811 ImGui::SameLine();
812 ImGui::TextColored(usage_color, "(%.1f%%)", usage_percentage);
813
814 ImGui::SetNextWindowViewportToCurrent();
815 ImGui::PlotLines("##TextureMemory",
816 texture_memory_samples.get_values(),
818 texture_memory_samples.get_offset(),
819 "Texture Memory Usage Over Time",
820 0.0f,
821 static_cast<float>(gpu_memory_max),
822 ImVec2(overlay_width, plot_height));
823 ImGui::Unindent();
824}
825
826} // namespace unravel
auto on_frame_ui_render(rtti::context &ctx, const char *name) -> void
Render the statistics panel UI.
auto on_frame_update(rtti::context &ctx, delta_t dt) -> void
Update the statistics panel logic each frame.
auto deinit(rtti::context &ctx) -> void
Deinitialize the statistics panel and clean up resources.
auto init(rtti::context &ctx) -> void
Initialize the statistics panel.
auto on_frame_render(rtti::context &ctx, delta_t dt) -> void
Render the statistics panel each frame.
static constexpr uint32_t NUM_SAMPLES
std::chrono::duration< float > delta_t
std::string name
Definition hub.cpp:27
#define ICON_MDI_CLOCK_OUTLINE
#define ICON_MDI_CUBE_OUTLINE
#define ICON_MDI_CHART_LINE
#define ICON_MDI_ARROW_DOWN_BOLD
#define ICON_MDI_PUZZLE
#define ICON_MDI_INFORMATION
void PushFont(Font::Enum _font)
Definition imgui.cpp:617
uint64_t GetDrawCalls()
Definition imgui.cpp:715
bgfx::Stats stats
Definition graphics.h:30
void set_debug(uint32_t _debug)
Definition graphics.cpp:311
const stats * get_stats()
Definition graphics.cpp:291
const caps * get_caps()
Definition graphics.cpp:286
bgfx::Caps caps
Definition graphics.h:29
auto draw_resource_bar(const char *name, const char *tooltip, uint32_t current_value, uint32_t max_value, float max_width, float height) -> void
Draw a resource usage bar with label and percentage.
auto draw_progress_bar(float width, float max_width, float height, const ImVec4 &color) -> bool
Draw a colored progress bar with hover effects.
auto get_app_profiler() -> performance_profiler *
Definition profiler.cpp:6
static auto get_last_frame_max_pass_id() -> gfx::view_id