mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-03-17 18:54:51 +01:00
The body was lagging behind the text. This was fixed by calling an updated version of init() on settings change. This introduced spikes in the frametime graph, so the data had to become members and m_force_update was adjusted to not interfere with data aquisition.
755 lines
19 KiB
C++
755 lines
19 KiB
C++
#include "stdafx.h"
|
|
#include "overlay_perf_metrics.h"
|
|
#include "Emu/RSX/RSXThread.h"
|
|
#include "Emu/Cell/SPUThread.h"
|
|
#include "Emu/Cell/RawSPUThread.h"
|
|
#include "Emu/Cell/PPUThread.h"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <charconv>
|
|
|
|
#include "util/sysinfo.hpp"
|
|
|
|
namespace rsx
|
|
{
|
|
namespace overlays
|
|
{
|
|
inline color4f convert_color_code(std::string hex_color, f32 opacity = 1.0f)
|
|
{
|
|
if (hex_color.length() > 0 && hex_color[0] == '#')
|
|
{
|
|
hex_color.erase(0, 1);
|
|
}
|
|
|
|
unsigned hexval = 0;
|
|
const auto len = hex_color.length();
|
|
|
|
if (len != 6 && len != 8)
|
|
{
|
|
rsx_log.error("Incompatible color code: '%s' has wrong length: %d", hex_color, len);
|
|
return color4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
// auto&& [ptr, ec] = std::from_chars(hex_color.c_str(), hex_color.c_str() + len, &hexval, 16);
|
|
|
|
// if (ptr != hex_color.c_str() + len || ec)
|
|
// {
|
|
// rsx_log.error("Overlays: tried to convert incompatible color code: '%s'", hex_color);
|
|
// return color4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
// }
|
|
for (u32 i = 0; i < len; i++)
|
|
{
|
|
hexval <<= 4;
|
|
|
|
switch (char c = hex_color[i])
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
hexval |= (c - '0');
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
hexval |= (c - 'a' + 10);
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
hexval |= (c - 'A' + 10);
|
|
break;
|
|
default:
|
|
{
|
|
rsx_log.error("Overlays: invalid characters in color code: '%s'", hex_color);
|
|
return color4f(0.0f, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int r = (len == 8 ? (hexval >> 24) : (hexval >> 16)) & 0xff;
|
|
const int g = (len == 8 ? (hexval >> 16) : (hexval >> 8)) & 0xff;
|
|
const int b = (len == 8 ? (hexval >> 8) : (hexval >> 0)) & 0xff;
|
|
const int a = len == 8 ? ((hexval >> 0) & 0xff) : 255;
|
|
|
|
return color4f(r / 255.f, g / 255.f, b / 255.f, a / 255.f * opacity);
|
|
}
|
|
|
|
void perf_metrics_overlay::reset_transform(label& elm, u16 bottom_margin) const
|
|
{
|
|
const u32 text_padding = m_font_size / 2;
|
|
|
|
// left, top, right, bottom
|
|
const areau padding { text_padding, text_padding - 4, text_padding, text_padding };
|
|
const positionu margin { m_margin_x, m_margin_y };
|
|
positionu pos;
|
|
|
|
const auto overlay_width = m_body.w + margin.x;
|
|
const auto overlay_height = m_body.h + margin.y;
|
|
|
|
switch (m_quadrant)
|
|
{
|
|
case screen_quadrant::top_left:
|
|
pos.x = margin.x;
|
|
pos.y = margin.y;
|
|
break;
|
|
case screen_quadrant::top_right:
|
|
pos.x = virtual_width - overlay_width;
|
|
pos.y = margin.y;
|
|
break;
|
|
case screen_quadrant::bottom_left:
|
|
pos.x = margin.x;
|
|
pos.y = virtual_height - overlay_height - bottom_margin;
|
|
break;
|
|
case screen_quadrant::bottom_right:
|
|
pos.x = virtual_width - overlay_width;
|
|
pos.y = virtual_height - overlay_height - bottom_margin;
|
|
break;
|
|
}
|
|
|
|
if (m_center_x)
|
|
{
|
|
pos.x = (virtual_width - m_body.w) / 2;
|
|
}
|
|
|
|
if (m_center_y)
|
|
{
|
|
pos.y = (virtual_height - m_body.h - bottom_margin) / 2;
|
|
}
|
|
|
|
elm.set_pos(pos.x, pos.y);
|
|
elm.set_padding(padding.x1, padding.x2, padding.y1, padding.y2);
|
|
}
|
|
|
|
void perf_metrics_overlay::reset_transforms()
|
|
{
|
|
const u16 perf_overlay_padding = m_font_size / 2;
|
|
|
|
const u16 fps_graph_h = 60;
|
|
const u16 frametime_graph_h = 45;
|
|
|
|
u16 bottom_margin{};
|
|
|
|
if (m_framerate_graph_enabled || m_frametime_graph_enabled)
|
|
{
|
|
// Adjust body size to account for the graphs
|
|
// TODO: Bit hacky, could do this with margins if overlay_element had bottom margin (or negative top at least)
|
|
bottom_margin = perf_overlay_padding;
|
|
|
|
if (m_framerate_graph_enabled)
|
|
{
|
|
m_fps_graph.set_size(m_fps_graph.w, fps_graph_h);
|
|
bottom_margin += m_fps_graph.get_height();
|
|
}
|
|
|
|
if (m_frametime_graph_enabled)
|
|
{
|
|
m_frametime_graph.set_size(m_frametime_graph.w, frametime_graph_h);
|
|
bottom_margin += m_frametime_graph.get_height();
|
|
}
|
|
}
|
|
|
|
// Set body/titles transform
|
|
if (m_force_repaint)
|
|
{
|
|
m_force_repaint = false;
|
|
reset_body(bottom_margin);
|
|
reset_titles(bottom_margin);
|
|
}
|
|
else
|
|
{
|
|
reset_transform(m_body, bottom_margin);
|
|
reset_transform(m_titles, bottom_margin);
|
|
}
|
|
|
|
if (m_framerate_graph_enabled || m_frametime_graph_enabled)
|
|
{
|
|
// Position the graphs within the body
|
|
const u16 graphs_width = m_body.w;
|
|
const u16 body_left = m_body.x;
|
|
u16 y_offset = m_body.y + m_body.h + perf_overlay_padding;
|
|
|
|
if (m_framerate_graph_enabled)
|
|
{
|
|
m_fps_graph.update();
|
|
m_fps_graph.set_pos(body_left, y_offset);
|
|
m_fps_graph.set_size(graphs_width, fps_graph_h);
|
|
|
|
y_offset += m_fps_graph.get_height();
|
|
}
|
|
|
|
if (m_frametime_graph_enabled)
|
|
{
|
|
m_frametime_graph.update();
|
|
m_frametime_graph.set_pos(body_left, y_offset);
|
|
m_frametime_graph.set_size(graphs_width, frametime_graph_h);
|
|
}
|
|
}
|
|
}
|
|
|
|
void perf_metrics_overlay::reset_body(u16 bottom_margin)
|
|
{
|
|
m_body.set_font(m_font.c_str(), m_font_size);
|
|
m_body.fore_color = convert_color_code(m_color_body, m_opacity);
|
|
m_body.back_color = convert_color_code(m_background_body, m_opacity);
|
|
reset_transform(m_body, bottom_margin);
|
|
}
|
|
|
|
void perf_metrics_overlay::reset_titles(u16 bottom_margin)
|
|
{
|
|
m_titles.set_font(m_font.c_str(), m_font_size);
|
|
m_titles.fore_color = convert_color_code(m_color_title, m_opacity);
|
|
m_titles.back_color = convert_color_code(m_background_title, m_opacity);
|
|
reset_transform(m_titles, bottom_margin);
|
|
|
|
switch (m_detail)
|
|
{
|
|
case detail_level::minimal:
|
|
case detail_level::low: m_titles.set_text(""); break;
|
|
case detail_level::medium: m_titles.set_text(fmt::format("\n\n%s", title1_medium)); break;
|
|
case detail_level::high: m_titles.set_text(fmt::format("\n\n%s\n\n\n\n\n\n%s", title1_high, title2)); break;
|
|
}
|
|
m_titles.auto_resize();
|
|
m_titles.refresh();
|
|
}
|
|
|
|
void perf_metrics_overlay::init()
|
|
{
|
|
reset_transforms();
|
|
force_next_update();
|
|
|
|
if (m_is_initialised)
|
|
{
|
|
update();
|
|
return;
|
|
}
|
|
|
|
m_update_timer.Start();
|
|
m_frametime_timer.Start();
|
|
|
|
update();
|
|
|
|
m_is_initialised = true;
|
|
visible = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_framerate_graph_enabled(bool enabled)
|
|
{
|
|
if (m_framerate_graph_enabled == enabled)
|
|
return;
|
|
|
|
m_framerate_graph_enabled = enabled;
|
|
|
|
if (enabled)
|
|
{
|
|
m_fps_graph.set_title(" Framerate");
|
|
m_fps_graph.set_font_size(static_cast<u16>(m_font_size * 0.8));
|
|
m_fps_graph.set_count(50);
|
|
m_fps_graph.set_color(convert_color_code(m_color_body, m_opacity));
|
|
m_fps_graph.set_guide_interval(10);
|
|
}
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_frametime_graph_enabled(bool enabled)
|
|
{
|
|
if (m_frametime_graph_enabled == enabled)
|
|
return;
|
|
|
|
m_frametime_graph_enabled = enabled;
|
|
|
|
if (enabled)
|
|
{
|
|
m_frametime_graph.set_title(" Frametime");
|
|
m_frametime_graph.set_font_size(static_cast<u16>(m_font_size * 0.8));
|
|
m_frametime_graph.set_count(170);
|
|
m_frametime_graph.set_color(convert_color_code(m_color_body, m_opacity));
|
|
m_frametime_graph.set_guide_interval(8);
|
|
}
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_detail_level(detail_level level)
|
|
{
|
|
if (m_detail == level)
|
|
return;
|
|
|
|
m_detail = level;
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_position(screen_quadrant quadrant)
|
|
{
|
|
if (m_quadrant == quadrant)
|
|
return;
|
|
|
|
m_quadrant = quadrant;
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
// In ms
|
|
void perf_metrics_overlay::set_update_interval(u32 update_interval)
|
|
{
|
|
m_update_interval = update_interval;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_font(std::string font)
|
|
{
|
|
if (m_font == font)
|
|
return;
|
|
|
|
m_font = std::move(font);
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_font_size(u16 font_size)
|
|
{
|
|
if (m_font_size == font_size)
|
|
return;
|
|
|
|
m_font_size = font_size;
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_margins(u32 margin_x, u32 margin_y, bool center_x, bool center_y)
|
|
{
|
|
if (m_margin_x == margin_x && m_margin_y == margin_y && m_center_x == center_x && m_center_y == center_y)
|
|
return;
|
|
|
|
m_margin_x = margin_x;
|
|
m_margin_y = margin_y;
|
|
m_center_x = center_x;
|
|
m_center_y = center_y;
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_opacity(f32 opacity)
|
|
{
|
|
if (m_opacity == opacity)
|
|
return;
|
|
|
|
m_opacity = opacity;
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_body_colors(std::string color, std::string background)
|
|
{
|
|
if (m_color_body == color && m_background_body == background)
|
|
return;
|
|
|
|
m_color_body = std::move(color);
|
|
m_background_body = std::move(background);
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::set_title_colors(std::string color, std::string background)
|
|
{
|
|
if (m_color_title == color && m_background_title == background)
|
|
return;
|
|
|
|
m_color_title = std::move(color);
|
|
m_background_title = std::move(background);
|
|
|
|
m_force_repaint = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::force_next_update()
|
|
{
|
|
m_force_update = true;
|
|
}
|
|
|
|
void perf_metrics_overlay::update()
|
|
{
|
|
const auto elapsed_update = m_update_timer.GetElapsedTimeInMilliSec();
|
|
|
|
if (m_is_initialised)
|
|
{
|
|
if (m_frametime_graph_enabled && !m_force_update)
|
|
{
|
|
const auto elapsed_frame = m_frametime_timer.GetElapsedTimeInMilliSec();
|
|
m_frametime_timer.Start();
|
|
m_frametime_graph.record_datapoint(static_cast<float>(elapsed_frame));
|
|
}
|
|
|
|
if (m_force_repaint)
|
|
{
|
|
reset_transforms();
|
|
}
|
|
}
|
|
|
|
if (!m_force_update)
|
|
{
|
|
++m_frames;
|
|
}
|
|
|
|
if (elapsed_update >= m_update_interval || m_force_update)
|
|
{
|
|
// 1. Fetch/calculate metrics we'll need
|
|
if (!m_is_initialised || !m_force_update)
|
|
{
|
|
m_update_timer.Start();
|
|
|
|
const auto rsx_thread = g_fxo->get<rsx::thread>();
|
|
|
|
switch (m_detail)
|
|
{
|
|
case detail_level::high:
|
|
{
|
|
m_frametime = std::max(0.f, static_cast<float>(elapsed_update / m_frames));
|
|
|
|
m_rsx_load = rsx_thread->get_load();
|
|
|
|
m_total_threads = CPUStats::get_thread_count();
|
|
|
|
[[fallthrough]];
|
|
}
|
|
case detail_level::medium:
|
|
{
|
|
m_ppus = idm::select<named_thread<ppu_thread>>([this](u32, named_thread<ppu_thread>& ppu)
|
|
{
|
|
m_ppu_cycles += thread_ctrl::get_cycles(ppu);
|
|
});
|
|
|
|
m_spus = idm::select<named_thread<spu_thread>>([this](u32, named_thread<spu_thread>& spu)
|
|
{
|
|
m_spu_cycles += thread_ctrl::get_cycles(spu);
|
|
});
|
|
|
|
m_rsx_cycles += rsx_thread->get_cycles();
|
|
|
|
m_total_cycles = std::max<u64>(1, m_ppu_cycles + m_spu_cycles + m_rsx_cycles);
|
|
m_cpu_usage = static_cast<f32>(m_cpu_stats.get_usage());
|
|
|
|
m_ppu_usage = std::clamp(m_cpu_usage * m_ppu_cycles / m_total_cycles, 0.f, 100.f);
|
|
m_spu_usage = std::clamp(m_cpu_usage * m_spu_cycles / m_total_cycles, 0.f, 100.f);
|
|
m_rsx_usage = std::clamp(m_cpu_usage * m_rsx_cycles / m_total_cycles, 0.f, 100.f);
|
|
|
|
[[fallthrough]];
|
|
}
|
|
case detail_level::low:
|
|
{
|
|
if (m_cpu_usage < 0.)
|
|
m_cpu_usage = static_cast<f32>(m_cpu_stats.get_usage());
|
|
|
|
[[fallthrough]];
|
|
}
|
|
case detail_level::minimal:
|
|
{
|
|
m_fps = std::max(0.f, static_cast<f32>(m_frames / (elapsed_update / 1000)));
|
|
if (m_is_initialised && m_framerate_graph_enabled)
|
|
m_fps_graph.record_datapoint(m_fps);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Format output string
|
|
std::string perf_text;
|
|
|
|
switch (m_detail)
|
|
{
|
|
case detail_level::minimal:
|
|
{
|
|
perf_text += fmt::format("FPS : %05.2f", m_fps);
|
|
break;
|
|
}
|
|
case detail_level::low:
|
|
{
|
|
perf_text += fmt::format("FPS : %05.2f\n"
|
|
"CPU : %04.1f %%",
|
|
m_fps, m_cpu_usage);
|
|
break;
|
|
}
|
|
case detail_level::medium:
|
|
{
|
|
perf_text += fmt::format("FPS : %05.2f\n\n"
|
|
"%s\n"
|
|
" PPU : %04.1f %%\n"
|
|
" SPU : %04.1f %%\n"
|
|
" RSX : %04.1f %%\n"
|
|
" Total : %04.1f %%",
|
|
m_fps, std::string(title1_medium.size(), ' '), m_ppu_usage, m_spu_usage, m_rsx_usage, m_cpu_usage, std::string(title2.size(), ' '));
|
|
break;
|
|
}
|
|
case detail_level::high:
|
|
{
|
|
perf_text += fmt::format("FPS : %05.2f (%03.1fms)\n\n"
|
|
"%s\n"
|
|
" PPU : %04.1f %% (%2u)\n"
|
|
" SPU : %04.1f %% (%2u)\n"
|
|
" RSX : %04.1f %% ( 1)\n"
|
|
" Total : %04.1f %% (%2u)\n\n"
|
|
"%s\n"
|
|
" RSX : %02u %%",
|
|
m_fps, m_frametime, std::string(title1_high.size(), ' '), m_ppu_usage, m_ppus, m_spu_usage, m_spus, m_rsx_usage, m_cpu_usage, m_total_threads, std::string(title2.size(), ' '), m_rsx_load);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_body.set_text(perf_text);
|
|
|
|
if (m_body.auto_resize())
|
|
{
|
|
reset_transforms();
|
|
}
|
|
|
|
m_body.refresh();
|
|
|
|
if (!m_force_update)
|
|
{
|
|
m_frames = 0;
|
|
}
|
|
else
|
|
{
|
|
// Only force once
|
|
m_force_update = false;
|
|
}
|
|
}
|
|
|
|
if (m_framerate_graph_enabled)
|
|
{
|
|
m_fps_graph.update();
|
|
}
|
|
|
|
if (m_frametime_graph_enabled)
|
|
{
|
|
m_frametime_graph.update();
|
|
}
|
|
}
|
|
|
|
compiled_resource perf_metrics_overlay::get_compiled()
|
|
{
|
|
if (!visible)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
compiled_resource compiled_resources = m_body.get_compiled();
|
|
|
|
compiled_resources.add(m_titles.get_compiled());
|
|
|
|
if (m_framerate_graph_enabled)
|
|
{
|
|
compiled_resources.add(m_fps_graph.get_compiled());
|
|
}
|
|
|
|
if (m_frametime_graph_enabled)
|
|
{
|
|
compiled_resources.add(m_frametime_graph.get_compiled());
|
|
}
|
|
|
|
return compiled_resources;
|
|
}
|
|
|
|
graph::graph()
|
|
{
|
|
m_label.set_font("e046323ms.ttf", 8);
|
|
m_label.fore_color = { 1.f, 1.f, 1.f, 1.f };
|
|
m_label.back_color = { 0.f, 0.f, 0.f, .7f };
|
|
|
|
back_color = { 0.f, 0.f, 0.f, 0.5f };
|
|
}
|
|
|
|
void graph::set_pos(u16 _x, u16 _y)
|
|
{
|
|
m_label.set_pos(_x, _y);
|
|
overlay_element::set_pos(_x, _y + m_label.h);
|
|
}
|
|
|
|
void graph::set_size(u16 _w, u16 _h)
|
|
{
|
|
overlay_element::set_size(_w, _h);
|
|
|
|
// Place label horizontally in the middle of the graph rect
|
|
const u16 label_x = std::max(x, u16(x + (w / 2) - (m_label.w / 2)));
|
|
m_label.set_pos(label_x, m_label.y);
|
|
}
|
|
|
|
void graph::set_title(const char* title)
|
|
{
|
|
m_title = title;
|
|
}
|
|
|
|
void graph::set_font(const char* font_name, u16 font_size)
|
|
{
|
|
m_label.set_font(font_name, font_size);
|
|
}
|
|
|
|
void graph::set_font_size(u16 font_size)
|
|
{
|
|
const auto font_name = m_label.get_font()->get_name().data();
|
|
m_label.set_font(font_name, font_size);
|
|
}
|
|
|
|
void graph::set_count(u32 datapoint_count)
|
|
{
|
|
m_datapoint_count = datapoint_count;
|
|
m_datapoints.resize(datapoint_count, 0);
|
|
}
|
|
|
|
void graph::set_color(color4f color)
|
|
{
|
|
m_color = color;
|
|
}
|
|
|
|
void graph::set_guide_interval(f32 guide_interval)
|
|
{
|
|
m_guide_interval = guide_interval;
|
|
}
|
|
|
|
u16 graph::get_height() const
|
|
{
|
|
return h + m_label.h + m_label.padding_top + m_label.padding_bottom;
|
|
}
|
|
|
|
void graph::record_datapoint(f32 datapoint)
|
|
{
|
|
ensure(datapoint >= 0.0f);
|
|
|
|
// std::dequeue is only faster for large sizes, so just use a std::vector and resize once in while
|
|
|
|
// Record datapoint
|
|
m_datapoints.push_back(datapoint);
|
|
|
|
// Calculate new min/max
|
|
// Make sure min/max reflects the data being displayed, not the entire datapoints vector
|
|
m_min = *std::min_element(m_datapoints.end() - m_datapoint_count, m_datapoints.end());
|
|
m_max = *std::max_element(m_datapoints.end() - m_datapoint_count, m_datapoints.end());
|
|
|
|
// Cull vector when it gets large
|
|
if (m_datapoints.size() > m_datapoint_count * 16ull)
|
|
{
|
|
std::copy(m_datapoints.begin() + m_datapoints.size() - m_datapoint_count, m_datapoints.end(), m_datapoints.begin());
|
|
m_datapoints.resize(m_datapoint_count);
|
|
}
|
|
}
|
|
|
|
void graph::update()
|
|
{
|
|
m_label.set_text(fmt::format("%s\nmn:%4.1f mx:%4.1f", m_title.c_str(), m_min, m_max));
|
|
m_label.set_padding(4, 4, 0, 4);
|
|
|
|
m_label.auto_resize();
|
|
m_label.refresh();
|
|
|
|
// If label horizontal end is larger, widen graph width to match it
|
|
set_size(std::max(m_label.w, w), h);
|
|
}
|
|
|
|
compiled_resource& graph::get_compiled()
|
|
{
|
|
refresh();
|
|
overlay_element::get_compiled();
|
|
|
|
const f32 normalize_factor = f32(h) / (m_max != 0.0f ? m_max : 1.0f);
|
|
|
|
// Don't show guide lines if they'd be more dense than 1 guide line every 3 pixels
|
|
const bool guides_too_dense = (m_max / m_guide_interval) > (h / 3.0f);
|
|
|
|
if (m_guide_interval > 0 && !guides_too_dense)
|
|
{
|
|
auto& cmd_guides = compiled_resources.append({});
|
|
auto& config_guides = cmd_guides.config;
|
|
|
|
config_guides.color = { 1.f, 1.f, 1.f, .2f };
|
|
config_guides.primitives = primitive_type::line_list;
|
|
|
|
auto& verts_guides = compiled_resources.draw_commands.back().verts;
|
|
|
|
for (auto y_off = m_guide_interval; y_off < m_max; y_off += m_guide_interval)
|
|
{
|
|
const f32 guide_y = y + y_off * normalize_factor;
|
|
verts_guides.emplace_back(x, guide_y);
|
|
verts_guides.emplace_back(static_cast<float>(x + w), guide_y);
|
|
}
|
|
}
|
|
|
|
auto& cmd_graph = compiled_resources.append({});
|
|
auto& config_graph = cmd_graph.config;
|
|
|
|
config_graph.color = m_color;
|
|
config_graph.primitives = primitive_type::line_strip;
|
|
|
|
auto& verts_graph = compiled_resources.draw_commands.back().verts;
|
|
|
|
const f32 x_stride = w * 1.f / m_datapoint_count;
|
|
const usz tail_index_offset = m_datapoints.size() - m_datapoint_count;
|
|
|
|
for (u32 i = 0; i < m_datapoint_count; ++i)
|
|
{
|
|
const f32 x_line = x + i * x_stride;
|
|
const f32 y_line = y + h - (m_datapoints[i + tail_index_offset] * normalize_factor);
|
|
verts_graph.emplace_back(x_line, y_line);
|
|
}
|
|
|
|
compiled_resources.add(m_label.get_compiled());
|
|
|
|
return compiled_resources;
|
|
}
|
|
|
|
void reset_performance_overlay()
|
|
{
|
|
if (!g_cfg.misc.use_native_interface)
|
|
return;
|
|
|
|
if (auto manager = g_fxo->get<rsx::overlays::display_manager>())
|
|
{
|
|
auto& perf_settings = g_cfg.video.perf_overlay;
|
|
auto perf_overlay = manager->get<rsx::overlays::perf_metrics_overlay>();
|
|
|
|
if (perf_settings.perf_overlay_enabled)
|
|
{
|
|
const bool existed = !!perf_overlay;
|
|
|
|
if (!existed)
|
|
{
|
|
perf_overlay = manager->create<rsx::overlays::perf_metrics_overlay>();
|
|
}
|
|
|
|
std::scoped_lock lock(*manager);
|
|
|
|
perf_overlay->set_detail_level(perf_settings.level);
|
|
perf_overlay->set_position(perf_settings.position);
|
|
perf_overlay->set_update_interval(perf_settings.update_interval);
|
|
perf_overlay->set_font(perf_settings.font);
|
|
perf_overlay->set_font_size(perf_settings.font_size);
|
|
perf_overlay->set_margins(perf_settings.margin_x, perf_settings.margin_y, perf_settings.center_x.get(), perf_settings.center_y.get());
|
|
perf_overlay->set_opacity(perf_settings.opacity / 100.f);
|
|
perf_overlay->set_body_colors(perf_settings.color_body, perf_settings.background_body);
|
|
perf_overlay->set_title_colors(perf_settings.color_title, perf_settings.background_title);
|
|
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->init();
|
|
}
|
|
else if (perf_overlay)
|
|
{
|
|
manager->remove<rsx::overlays::perf_metrics_overlay>();
|
|
}
|
|
}
|
|
}
|
|
} // namespace overlays
|
|
} // namespace rsx
|