diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 45bb6be7b3..31222f91a5 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -1131,9 +1131,15 @@ namespace rsx color4f m_color; f32 m_min{}; f32 m_max{}; + f32 m_avg{}; + f32 m_1p{}; f32 m_guide_interval{}; label m_label{}; + bool m_show_min_max{false}; + bool m_show_1p_avg{false}; + bool m_1p_sort_high{false}; + public: graph(); void set_pos(u16 _x, u16 _y) override; @@ -1144,6 +1150,8 @@ namespace rsx void set_count(u32 datapoint_count); void set_color(color4f color); void set_guide_interval(f32 guide_interval); + void set_labels_visible(bool show_min_max, bool show_1p_avg); + void set_one_percent_sort_high(bool sort_1p_high); u16 get_height() const; u32 get_datapoint_count() const; void record_datapoint(f32 datapoint); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp index 9719c5428f..57306074f3 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp @@ -244,6 +244,9 @@ namespace rsx void perf_metrics_overlay::init() { + m_fps_graph.set_one_percent_sort_high(false); + m_frametime_graph.set_one_percent_sort_high(true); + reset_transforms(); force_next_update(); @@ -271,7 +274,7 @@ namespace rsx if (enabled) { - m_fps_graph.set_title(" Framerate"); + m_fps_graph.set_title("Framerate: 00.0"); m_fps_graph.set_font_size(static_cast(m_font_size * 0.8)); m_fps_graph.set_color(convert_color_code(m_color_body, m_opacity)); m_fps_graph.set_guide_interval(10); @@ -289,7 +292,7 @@ namespace rsx if (enabled) { - m_frametime_graph.set_title(" Frametime"); + m_frametime_graph.set_title("Frametime: 0.0"); m_frametime_graph.set_font_size(static_cast(m_font_size * 0.8)); m_frametime_graph.set_color(convert_color_code(m_color_body, m_opacity)); m_frametime_graph.set_guide_interval(8); @@ -316,6 +319,18 @@ namespace rsx m_force_repaint = true; } + void perf_metrics_overlay::set_graph_detail_levels(perf_graph_detail_level framerate_level, perf_graph_detail_level frametime_level) + { + m_fps_graph.set_labels_visible( + framerate_level == perf_graph_detail_level::show_all || framerate_level == perf_graph_detail_level::show_min_max, + framerate_level == perf_graph_detail_level::show_all || framerate_level == perf_graph_detail_level::show_one_percent_avg); + m_frametime_graph.set_labels_visible( + frametime_level == perf_graph_detail_level::show_all || frametime_level == perf_graph_detail_level::show_min_max, + frametime_level == perf_graph_detail_level::show_all || frametime_level == perf_graph_detail_level::show_one_percent_avg); + + m_force_repaint = true; + } + void perf_metrics_overlay::set_detail_level(detail_level level) { if (m_detail == level) @@ -420,9 +435,10 @@ namespace rsx { if (m_frametime_graph_enabled && !m_force_update) { - const auto elapsed_frame = m_frametime_timer.GetElapsedTimeInMilliSec(); + const float elapsed_frame = static_cast(m_frametime_timer.GetElapsedTimeInMilliSec()); m_frametime_timer.Start(); - m_frametime_graph.record_datapoint(static_cast(elapsed_frame)); + m_frametime_graph.record_datapoint(elapsed_frame); + m_frametime_graph.set_title(fmt::format("Frametime: %4.1f", elapsed_frame).c_str()); } if (m_force_repaint) @@ -495,7 +511,10 @@ namespace rsx { m_fps = std::max(0.f, static_cast(m_frames / (elapsed_update / 1000))); if (m_is_initialised && m_framerate_graph_enabled) + { m_fps_graph.record_datapoint(m_fps); + m_fps_graph.set_title(fmt::format("Framerate: %04.1f", m_fps).c_str()); + } break; } } @@ -680,6 +699,17 @@ namespace rsx m_guide_interval = guide_interval; } + void graph::set_labels_visible(bool show_min_max, bool show_1p_avg) + { + m_show_min_max = show_min_max; + m_show_1p_avg = show_1p_avg; + } + + void graph::set_one_percent_sort_high(bool sort_1p_high) + { + m_1p_sort_high = sort_1p_high; + } + u16 graph::get_height() const { return h + m_label.h + m_label.padding_top + m_label.padding_bottom; @@ -699,23 +729,53 @@ namespace rsx // Record datapoint m_datapoints.push_back(datapoint); - // Calculate new min/max - m_min = max_v; m_max = 0.0f; + m_avg = 0.0f; + m_1p = 0.0f; - // Make sure min/max reflects the data being displayed, not the entire datapoints vector - for (usz i = m_datapoints.size() - m_datapoint_count; i < m_datapoints.size(); i++) + if (m_show_min_max || m_show_1p_avg) { - const f32& dp = m_datapoints[i]; + m_min = max_v; - if (dp < 0) continue; // Skip initial negative values. They don't count. + std::vector valid_datapoints; - m_min = std::min(m_min, dp); - m_max = std::max(m_max, dp); + // Make sure min/max reflects the data being displayed, not the entire datapoints vector + for (usz i = m_datapoints.size() - m_datapoint_count; i < m_datapoints.size(); i++) + { + const f32& dp = m_datapoints[i]; + + if (dp < 0) continue; // Skip initial negative values. They don't count. + + m_min = std::min(m_min, dp); + m_max = std::max(m_max, dp); + m_avg += dp; + + valid_datapoints.push_back(dp); + } + + // Sanitize min value + m_min = std::min(m_min, m_max); + + if (m_show_1p_avg && valid_datapoints.size()) + { + // Sort datapoints (we are only interested in the lowest/highest 1%) + const usz i_1p = valid_datapoints.size() / 100; + const usz n_1p = i_1p + 1; + + if (m_1p_sort_high) + std::nth_element(valid_datapoints.begin(), valid_datapoints.begin() + i_1p, valid_datapoints.end(), std::greater()); + else + std::nth_element(valid_datapoints.begin(), valid_datapoints.begin() + i_1p, valid_datapoints.end()); + + // Calculate statistics + m_avg /= valid_datapoints.size(); + m_1p = std::accumulate(valid_datapoints.begin(), valid_datapoints.begin() + n_1p, 0.0f) / static_cast(n_1p); + } + } + else + { + m_min = 0.0f; } - - // Sanitize min value - m_min = std::min(m_min, m_max); // Cull vector when it gets large if (m_datapoints.size() > m_datapoint_count * 16ull) @@ -727,7 +787,19 @@ namespace rsx void graph::update() { - m_label.set_text(fmt::format("%s\nmn:%4.1f mx:%4.1f", m_title.c_str(), m_min, m_max)); + std::string fps_info = m_title; + + if (m_show_1p_avg) + { + fmt::append(fps_info, "\n1%%:%4.1f av:%4.1f", m_1p, m_avg); + } + + if (m_show_min_max) + { + fmt::append(fps_info, "\nmn:%4.1f mx:%4.1f", m_min, m_max); + } + + m_label.set_text(fps_info); m_label.set_padding(4, 4, 0, 4); m_label.auto_resize(); @@ -827,6 +899,7 @@ namespace rsx perf_overlay->set_frametime_datapoint_count(perf_settings.frametime_datapoint_count); perf_overlay->set_framerate_graph_enabled(perf_settings.framerate_graph_enabled.get()); perf_overlay->set_frametime_graph_enabled(perf_settings.frametime_graph_enabled.get()); + perf_overlay->set_graph_detail_levels(perf_settings.framerate_graph_detail_level.get(), perf_settings.frametime_graph_detail_level.get()); perf_overlay->init(); } else if (perf_overlay) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.h b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.h index 4d24e621cd..587f153332 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.h @@ -89,6 +89,7 @@ namespace rsx void set_frametime_graph_enabled(bool enabled); void set_framerate_datapoint_count(u32 datapoint_count); void set_frametime_datapoint_count(u32 datapoint_count); + void set_graph_detail_levels(perf_graph_detail_level framerate_level, perf_graph_detail_level frametime_level); void set_detail_level(detail_level level); void set_position(screen_quadrant quadrant); void set_update_interval(u32 update_interval); diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 037b281eca..7a5c113e45 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -190,6 +190,8 @@ struct cfg_root : cfg::node cfg::uint<2, 6000> framerate_datapoint_count{ this, "Framerate datapoints", 50, true }; cfg::uint<2, 6000> frametime_datapoint_count{ this, "Frametime datapoints", 170, true }; cfg::_enum level{ this, "Detail level", detail_level::medium, true }; + cfg::_enum framerate_graph_detail_level{ this, "Framerate graph detail level", perf_graph_detail_level::show_all, true }; + cfg::_enum frametime_graph_detail_level{ this, "Frametime graph detail level", perf_graph_detail_level::show_all, true }; cfg::uint<1, 1000> update_interval{ this, "Metrics update interval (ms)", 350, true }; cfg::uint<4, 36> font_size{ this, "Font size (px)", 10, true }; cfg::_enum position{ this, "Position", screen_quadrant::top_left, true }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index 5e7b07e716..104a8940b6 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -143,6 +143,23 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](perf_graph_detail_level value) + { + switch (value) + { + case perf_graph_detail_level::minimal: return "Minimal"; + case perf_graph_detail_level::show_min_max: return "Show min and max"; + case perf_graph_detail_level::show_one_percent_avg: return "Show 1% and average"; + case perf_graph_detail_level::show_all: return "All"; + } + + return unknown; + }); +} + template <> void fmt_class_string::format(std::string& out, u64 arg) { diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index 52c8e16934..6a8c87f772 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -208,3 +208,11 @@ enum class thread_scheduler_mode old, alt }; + +enum class perf_graph_detail_level +{ + minimal, + show_min_max, + show_one_percent_avg, + show_all +}; diff --git a/rpcs3/Input/hid_pad_handler.cpp b/rpcs3/Input/hid_pad_handler.cpp index 467fa81f39..b4fc221f1f 100644 --- a/rpcs3/Input/hid_pad_handler.cpp +++ b/rpcs3/Input/hid_pad_handler.cpp @@ -53,7 +53,7 @@ bool hid_pad_handler::Init() if (res != 0) fmt::throw_exception("%s hidapi-init error.threadproc", m_type); - for (size_t i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI + for (usz i = 1; i <= MAX_GAMEPADS; i++) // Controllers 1-n in GUI { m_controllers.emplace(m_name_string + std::to_string(i), std::make_shared()); } @@ -167,7 +167,7 @@ void hid_pad_handler::enumerate_devices() } else { - const size_t count = std::count_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); + const usz count = std::count_if(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) { return c.second && c.second->hidDevice; }); if (count > 0) { hid_log.success("%s Controllers found: %d", m_type, count); diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 0086b1b6de..bf1758b036 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -499,7 +499,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) default: break; } - if (const size_t pos = std::basic_string_view(res.data(), 2).find_last_not_of(umax); pos != umax) + if (const usz pos = std::basic_string_view(res.data(), 2).find_last_not_of(umax); pos != umax) m_debugger_list->ShowAddress(res[pos] - std::max(row, 0) * 4, true, true); return; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 6e70e1ca74..ee24130269 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -686,7 +686,7 @@ void main_window::HandlePackageInstallation(QStringList file_paths) bool cancelled = false; - for (size_t i = 0, count = packages.size(); i < count; i++) + for (usz i = 0, count = packages.size(); i < count; i++) { progress = 0.;