ImGui::PlotTwoLines() extension, PerformanceInfo improvements
This commit is contained in:
142
openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp
Normal file
142
openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "ImGuiPlotTwoLines.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
void PlotTwoLines(const char* label,
|
||||
float (*getter1)(void* data, int idx), void* data1, const char *tooltipPrefix1,
|
||||
float (*getter2)(void* data, int idx), void* data2, const char *tooltipPrefix2,
|
||||
int values_count, float scale_min, float scale_max, ImVec2 graph_size)
|
||||
{
|
||||
ImGuiContext& g = *ImGui::GetCurrentContext();
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
const ImGuiStyle& style = g.Style;
|
||||
|
||||
ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
|
||||
if (graph_size.x == 0.0f)
|
||||
graph_size.x = ImGui::CalcItemWidth();
|
||||
if (graph_size.y == 0.0f)
|
||||
graph_size.y = label_size.y + (style.FramePadding.y * 2);
|
||||
|
||||
ImRect frame_bb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x + graph_size.x, window->DC.CursorPos.y + graph_size.y));
|
||||
ImRect inner_bb(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), ImVec2(frame_bb.Max.x - style.FramePadding.x, frame_bb.Max.y - style.FramePadding.y));
|
||||
ImRect total_bb(frame_bb.Min, ImVec2(frame_bb.Max.x + (label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f), frame_bb.Max.y));
|
||||
|
||||
ImGui::ItemSize(total_bb, style.FramePadding.y);
|
||||
if (!ImGui::ItemAdd(total_bb, 0))
|
||||
return;
|
||||
|
||||
// Determine scale from inputs if not specified
|
||||
if (scale_min == FLT_MAX || scale_max == FLT_MAX)
|
||||
{
|
||||
float v1_min = FLT_MAX, v1_max = -FLT_MAX;
|
||||
for (int i = 0; i < values_count; i++)
|
||||
{
|
||||
float v = getter1(data1, i);
|
||||
if (v != v) // Ignore NaN values
|
||||
continue;
|
||||
v1_min = ImMin(v1_min, v);
|
||||
v1_max = ImMax(v1_max, v);
|
||||
}
|
||||
float v2_min = FLT_MAX, v2_max = -FLT_MAX;
|
||||
for (int i = 0; i < values_count; i++)
|
||||
{
|
||||
float v = getter2(data2, i);
|
||||
if (v != v) // Ignore NaN values
|
||||
continue;
|
||||
v2_min = ImMin(v2_min, v);
|
||||
v2_max = ImMax(v2_max, v);
|
||||
}
|
||||
if (scale_min == FLT_MAX) scale_min = ImMin(v1_min, v2_min);
|
||||
if (scale_max == FLT_MAX) scale_max = ImMax(v1_max, v2_max);
|
||||
}
|
||||
|
||||
ImGui::RenderFrame(frame_bb.Min, frame_bb.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
int res_w = ImMin((int)graph_size.x, values_count); // Number of samples
|
||||
|
||||
if (res_w <= 0)
|
||||
return;
|
||||
|
||||
// Tooltip on hover
|
||||
int v_hovered = -1;
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
|
||||
const int v_idx = (int)(t * values_count);
|
||||
IM_ASSERT(v_idx >= 0 && v_idx < values_count);
|
||||
|
||||
const float v0 = getter1(data1, v_idx);
|
||||
const float v1 = getter2(data2, v_idx);
|
||||
ImGui::SetTooltip("%d: (%s: %8.4g, %s: %8.4g)", v_idx, tooltipPrefix1, v0, tooltipPrefix2, v1);
|
||||
v_hovered = v_idx;
|
||||
}
|
||||
|
||||
const float t_step = 1.0f / res_w;
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
draw_list->PushClipRect(inner_bb.Min, inner_bb.Max, true);
|
||||
|
||||
ImColor col1 = ImColor(255, 100, 100);
|
||||
ImColor col2 = ImColor(100, 255, 100);
|
||||
|
||||
// Plot first line
|
||||
for (int n = 0; n < res_w; n++)
|
||||
{
|
||||
const float t0 = t_step * (n + 0);
|
||||
const float t1 = t_step * (n + 1);
|
||||
const int v_idx0 = (int)(t0 * values_count);
|
||||
int v_idx1 = (int)(t1 * values_count);
|
||||
if(v_idx1 >= values_count)
|
||||
v_idx1 = values_count - 1;
|
||||
|
||||
IM_ASSERT(v_idx0 >= 0 && v_idx0 < values_count);
|
||||
IM_ASSERT(v_idx1 >= 0 && v_idx1 < values_count);
|
||||
|
||||
const float v0 = getter1(data1, v_idx0);
|
||||
const float v1 = getter1(data1, v_idx1);
|
||||
const float x0 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t0);
|
||||
const float x1 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t1);
|
||||
const float y0 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v0 - scale_min) / (scale_max - scale_min));
|
||||
const float y1 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v1 - scale_min) / (scale_max - scale_min));
|
||||
draw_list->AddLine(ImVec2(x0, y0), ImVec2(x1, y1), col1);
|
||||
}
|
||||
|
||||
// Plot second line
|
||||
for (int n = 0; n < res_w; n++)
|
||||
{
|
||||
const float t0 = t_step * (n + 0);
|
||||
const float t1 = t_step * (n + 1);
|
||||
const int v_idx0 = (int)(t0 * values_count);
|
||||
int v_idx1 = (int)(t1 * values_count);
|
||||
if(v_idx1 >= values_count)
|
||||
v_idx1 = values_count - 1;
|
||||
|
||||
IM_ASSERT(v_idx0 >= 0 && v_idx0 < values_count);
|
||||
IM_ASSERT(v_idx1 >= 0 && v_idx1 < values_count);
|
||||
|
||||
const float v0 = getter2(data2, v_idx0);
|
||||
const float v1 = getter2(data2, v_idx1);
|
||||
const float x0 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t0);
|
||||
const float x1 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t1);
|
||||
const float y0 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v0 - scale_min) / (scale_max - scale_min));
|
||||
const float y1 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v1 - scale_min) / (scale_max - scale_min));
|
||||
draw_list->AddLine(ImVec2(x0, y0), ImVec2(x1, y1), col2);
|
||||
}
|
||||
|
||||
draw_list->PopClipRect();
|
||||
|
||||
if (label_size.x > 0.0f)
|
||||
ImGui::RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
void PlotTwoLines(const char* label,
|
||||
float (*getter1)(void* data, int idx), void* data1, const char *tooltipPrefix1,
|
||||
float (*getter2)(void* data, int idx), void* data2, const char *tooltipPrefix2,
|
||||
int values_count, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
|
||||
}
|
||||
@@ -10,17 +10,20 @@
|
||||
#include "Host/SystemInfo.hpp"
|
||||
#include "Math/ByteSize.hpp"
|
||||
#include "ImGuiExtensions/ImGuiTextFmt.hpp"
|
||||
#include "ImGuiExtensions/ImGuiPlotTwoLines.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace OpenVulkano::Scene::UI
|
||||
{
|
||||
namespace
|
||||
{
|
||||
float FloatValuesGetter(void *data, int index)
|
||||
float FrameCollectionValuesGetter(void *data, int index)
|
||||
{
|
||||
auto queue = reinterpret_cast<std::deque<float> *>(data);
|
||||
return (*queue)[index];
|
||||
auto frameCollection = reinterpret_cast<FrameTimeCollection *>(data);
|
||||
float value = frameCollection->m_frameTimes[index];
|
||||
float result = value / frameCollection->m_maxValue * 100;
|
||||
return result;
|
||||
}
|
||||
|
||||
float RamValuesGetter(void *data, int index)
|
||||
@@ -31,16 +34,25 @@ namespace OpenVulkano::Scene::UI
|
||||
float percentage = used / max * 100;
|
||||
return percentage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PerformanceInfo::UpdateQueues()
|
||||
{
|
||||
m_frameTimes.push_back(static_cast<float>(CURRENT_FRAME.frameTime));
|
||||
while(m_frameTimes.size() > m_frameCount)
|
||||
m_frameTimes.pop_front();
|
||||
m_frameCollection.m_frameTimes.push_back(static_cast<float>(CURRENT_FRAME.frameTime));
|
||||
while(m_frameCollection.m_frameTimes.size() > m_windowSize)
|
||||
m_frameCollection.m_frameTimes.pop_front();
|
||||
|
||||
float maxFrameTime = FLT_MIN;
|
||||
for(auto value : m_frameCollection.m_frameTimes)
|
||||
{
|
||||
if(value > maxFrameTime)
|
||||
maxFrameTime = value;
|
||||
}
|
||||
m_frameCollection.m_maxValue = maxFrameTime;
|
||||
|
||||
m_ramUsed.push_back(static_cast<float>(SystemInfo::GetAppRamUsed()));
|
||||
while(m_ramUsed.size() > m_ramUsageCount)
|
||||
while(m_ramUsed.size() > m_windowSize)
|
||||
m_ramUsed.pop_front();
|
||||
}
|
||||
|
||||
@@ -53,24 +65,21 @@ namespace OpenVulkano::Scene::UI
|
||||
void PerformanceInfo::Draw()
|
||||
{
|
||||
UpdateQueues();
|
||||
assert(m_frameCollection.m_frameTimes.size() == m_ramUsed.size());
|
||||
|
||||
ImGui::Text("Last Frame Time(wrt max): %f s", m_frameCollection.m_frameTimes.back());
|
||||
ImGui::Text("Last FPS: %f", 1 / m_frameCollection.m_frameTimes.back());
|
||||
ImGui::SliderInt("Window Size", &m_windowSize, 10, 1000);
|
||||
ImGui::TextFmt("RAM: {} / {}, Free: {}", ByteSize(m_ramUsed.back()), ByteSize(SystemInfo::GetAppRamMax()), ByteSize(SystemInfo::GetAppRamAvailable()));
|
||||
|
||||
ImVec2 availableSize = ImGui::GetContentRegionAvail();
|
||||
availableSize.y *= 1/3.;
|
||||
|
||||
ImGui::Text("Last Frame Time: %f s", m_frameTimes.back());
|
||||
ImGui::Text("Last FPS: %f", 1 / m_frameTimes.back());
|
||||
ImGui::SliderInt("Window Size", &m_frameCount, 10, 1000);
|
||||
ImGui::PlotLines("", &FloatValuesGetter, &m_frameTimes, (int)m_frameTimes.size(), 0, nullptr, FLT_MAX, FLT_MAX, availableSize);
|
||||
|
||||
if(ImGui::CollapsingHeader("RAM Usage"))
|
||||
{
|
||||
ImGui::TextFmt("RAM: {} / {}, Free: {}", ByteSize(m_ramUsed.back()), ByteSize(SystemInfo::GetAppRamMax()), ByteSize(SystemInfo::GetAppRamAvailable()));
|
||||
|
||||
ImGui::SliderInt("Window Size ", &m_ramUsageCount, 10, 1000);
|
||||
float scaleMin = 0.01;
|
||||
float scaleMax = 100;
|
||||
ImGui::PlotLines("", &RamValuesGetter, &m_ramUsed, (int)m_ramUsed.size(), 0, nullptr, scaleMin, scaleMax, availableSize);
|
||||
}
|
||||
float scaleMin = 0.01;
|
||||
float scaleMax = 100;
|
||||
ImGui::PlotTwoLines("",
|
||||
&FrameCollectionValuesGetter, &m_frameCollection, "Frame Time",
|
||||
&RamValuesGetter, &m_ramUsed, "RAM",
|
||||
(int)m_ramUsed.size(),
|
||||
scaleMin, scaleMax, availableSize);
|
||||
}
|
||||
|
||||
void PerformanceInfo::EndDraw()
|
||||
|
||||
@@ -12,13 +12,17 @@
|
||||
|
||||
namespace OpenVulkano::Scene::UI
|
||||
{
|
||||
struct FrameTimeCollection
|
||||
{
|
||||
std::deque<float> m_frameTimes;
|
||||
float m_maxValue;
|
||||
};
|
||||
|
||||
class PerformanceInfo : public UiElement
|
||||
{
|
||||
int m_frameCount = 200;
|
||||
std::deque<float> m_frameTimes;
|
||||
|
||||
int m_ramUsageCount = 200;
|
||||
int m_windowSize = 200;
|
||||
std::deque<float> m_ramUsed;
|
||||
FrameTimeCollection m_frameCollection;
|
||||
|
||||
void UpdateQueues();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user