Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `fps_only` | Show FPS only. ***Not meant to be used with other display params*** |
| `fps_sampling_period=` | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500` |
| `fps_value` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` |
| `fps_metrics` | Takes a list of decimal values or the value avg, e.g `avg,0.001` |
| `fps_metrics` | Takes a list of decimal percentile values, `avg`, or `cv`. CV is the population standard deviation divided by mean frametime, in percent; lower is steadier. E.g. `avg,0.001,cv` |
| `reset_fps_metrics` | Reset fps metrics keybind, default is `Shift_R+F9` |
| `fps_text` | Display custom text for engine name in front of FPS |
| `frame_count` | Display frame count |
Expand Down
5 changes: 3 additions & 2 deletions data/MangoHud.conf
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ fps
# fps_text=""
frametime
# frame_count
## fps_metrics takes a list of decimal values or the value avg
# fps_metrics=avg,0.01
## fps_metrics takes a list of decimal percentile values, avg, or cv
## cv is the population standard deviation divided by mean frametime, in percent; lower is steadier
# fps_metrics=avg,0.01,cv

### Display GPU throttling status based on Power, current, temp or "other"
## Only shows if throttling is currently happening
Expand Down
40 changes: 37 additions & 3 deletions src/fps_metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@
#include <condition_variable>
#include <stdexcept>
#include <iomanip>
#include <cmath>
#include <spdlog/spdlog.h>

enum class fps_metric_unit {
fps,
percent,
};

struct metric_t {
std::string name;
float value;
std::string display_name;
fps_metric_unit unit = fps_metric_unit::fps;
};

class fpsMetrics {
Expand Down Expand Up @@ -50,8 +57,27 @@ class fpsMetrics {
if (frametimes.empty())
return;

std::vector<float> sorted_values = frametimes;
std::sort(sorted_values.begin(), sorted_values.end(), std::greater<float>());
const bool has_cv = std::any_of(metrics.begin(), metrics.end(), [](const auto& metric) {
return metric.name == "CV";
});
double mean = 0.0;
double m2 = 0.0;
if (has_cv) {
mean = std::accumulate(frametimes.begin(), frametimes.end(), 0.0) / frametimes.size();
for (const float frametime : frametimes) {
const double delta = frametime - mean;
m2 += delta * delta;
}
}

const bool needs_sorted_values = std::any_of(metrics.begin(), metrics.end(), [](const auto& metric) {
return metric.name != "CV";
});
std::vector<float> sorted_values;
if (needs_sorted_values) {
sorted_values = frametimes;
std::sort(sorted_values.begin(), sorted_values.end(), std::greater<float>());
}

auto it = metrics.begin();
while (it != metrics.end()) {
Expand All @@ -64,6 +90,9 @@ class fpsMetrics {

float avg = 1000.f / (sum / sorted_values.size());
it->value = avg;
} else if (it->name == "CV") {
const double variance = m2 / frametimes.size();
it->value = mean > 0.0 ? 100.0 * std::sqrt(variance) / mean : 0.0;
} else {
try {
float val = std::stof(it->name);
Expand Down Expand Up @@ -100,7 +129,12 @@ class fpsMetrics {
for(char& c : val) {
c = std::toupper(static_cast<unsigned char>(c));
}
_metrics.push_back({val, 0.0f});
metric_t metric {val, 0.0f, {}};
if (val == "CV") {
metric.display_name = val;
metric.unit = fps_metric_unit::percent;
}
_metrics.push_back(metric);
}
return _metrics;
}
Expand Down
8 changes: 5 additions & 3 deletions src/hud_elements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,11 +1655,13 @@ void HudElements::fps_metrics(){
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.engine, "%s", metric.display_name.c_str());
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", metric.value);
const bool is_percent = metric.unit == fps_metric_unit::percent;
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width,
is_percent ? "%.2f" : "%.0f", metric.value);
ImGui::SameLine(0, 1.0f);
if(!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript]){
if (is_percent || !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript]){
ImGui::PushFont(HUDElements.sw_stats->font_small);
HUDElements.TextColored(HUDElements.colors.text, "FPS");
HUDElements.TextColored(HUDElements.colors.text, "%s", is_percent ? "%" : "FPS");
ImGui::PopFont();
}
ImguiNextColumnOrNewRow();
Expand Down
6 changes: 1 addition & 5 deletions src/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,18 +362,14 @@ void Logger::calculate_benchmark_data(){
for (auto& point : m_log_array)
fps_values.push_back(point.frametime);

benchmark.percentile_data.clear();

std::vector<std::string> metrics {"0.97", "avg", "0.01", "0.001"};
std::unique_ptr<fpsMetrics> fpsmetrics;
auto params = get_params();
if (!params->fps_metrics.empty())
metrics = params->fps_metrics;

fpsmetrics = std::make_unique<fpsMetrics>(metrics, fps_values);
auto metrics_copy = fpsmetrics->copy_metrics();
for (auto& metric : metrics_copy)
benchmark.percentile_data.push_back({metric.display_name, metric.value});
benchmark.metrics = fpsmetrics->copy_metrics();

fpsmetrics.reset();
}
16 changes: 10 additions & 6 deletions src/overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
#endif
frametime = frametime_ms;
fps = double(1000 / frametime_ms);
if (fpsmetrics) fpsmetrics->update(frametime_ms);
if (fpsmetrics && sw_stats.last_present_time)
fpsmetrics->update(frametime_ms);

if (elapsed >= real_params->fps_sampling_period) {
if (!hw_update_thread)
Expand Down Expand Up @@ -541,7 +542,7 @@ void render_mpris_metadata(const struct overlay_params& params, mutexed_metadata

static void render_benchmark(swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size, unsigned height, Clock::time_point now){
// TODO, FIX LOG_DURATION FOR BENCHMARK
int benchHeight = (2 + benchmark.percentile_data.size()) * real_font_size.x + 10.0f + 58;
int benchHeight = (2 + benchmark.metrics.size()) * real_font_size.x + 10.0f + 58;
ImGui::SetNextWindowSize(ImVec2(window_size.x, benchHeight), ImGuiCond_Always);
if (height - (window_size.y + data.main_window_pos.y + 5) < benchHeight)
ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y - benchHeight - 5), ImGuiCond_Always);
Expand Down Expand Up @@ -589,11 +590,14 @@ static void render_benchmark(swapchain_stats& data, const struct overlay_params&
snprintf(duration, sizeof(duration), "Duration: %.1fs", std::chrono::duration<float>(logger->last_log_end() - logger->last_log_begin()).count());
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(duration).x / 2));
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", duration);
for (auto& data_ : benchmark.percentile_data){
char buffer[20];
snprintf(buffer, sizeof(buffer), "%s %.1f", data_.first.c_str(), data_.second);
for (const auto& metric : benchmark.metrics){
char buffer[32];
if (metric.unit == fps_metric_unit::percent)
snprintf(buffer, sizeof(buffer), "%s %.2f%%", metric.display_name.c_str(), metric.value);
else
snprintf(buffer, sizeof(buffer), "%s %.1f", metric.display_name.c_str(), metric.value);
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(buffer).x / 2));
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s %.1f", data_.first.c_str(), data_.second);
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", buffer);
}

float max = benchmark.fps_data.empty() ? 0.0f : *max_element(benchmark.fps_data.begin(), benchmark.fps_data.end());
Expand Down
3 changes: 2 additions & 1 deletion src/overlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <deque>
#include <imgui.h>
#include "imgui_internal.h"
#include "fps_metrics.h"
#include "overlay_params.h"
#include "hud_elements.h"

Expand Down Expand Up @@ -80,7 +81,7 @@ struct swapchain_stats {
struct benchmark_stats {
float total;
std::vector<float> fps_data;
std::vector<std::pair<std::string, float>> percentile_data;
std::vector<metric_t> metrics;
};

struct LOAD_DATA {
Expand Down