From 6a010d8eabde642148527064f71e2c0f94502cb2 Mon Sep 17 00:00:00 2001 From: PMunkes Date: Tue, 19 Apr 2022 19:37:29 +0200 Subject: [PATCH] Introduce FCAT overlay support This introduces support to overlay FCAT markers on top of other HUD elements. For more information about nVidia's FCAT tool see: https://nvidia.com/en-us/geforce/technologies/fcat/technology This patch includes support for the existing parameter infrastructure and it is fully dynamic. Squashed commit: Refactor FCAT to use existing parameter handling infrastructure With this patch the FCAT overlay should be hooked up into the normal parameter handling infrastructure. This includes support for configuration file options, which are also part of this commit. --- bin/MangoHud.conf | 11 ++++++++ src/fcat.h | 63 ++++++++++++++++++++++++++++++++++++++++++ src/overlay.cpp | 19 +++++++++++++ src/overlay_params.cpp | 5 ++++ src/overlay_params.h | 5 ++++ 5 files changed, 103 insertions(+) create mode 100644 src/fcat.h diff --git a/bin/MangoHud.conf b/bin/MangoHud.conf index 24943c95..afd3b2f3 100644 --- a/bin/MangoHud.conf +++ b/bin/MangoHud.conf @@ -166,6 +166,17 @@ frame_timing # background_alpha=0.5 # alpha= +### FCAT overlay +### This enables an FCAT overlay to perform frametime analysis on the final image stream. +### Enable the overlay +# fcat +### Set the width of the FCAT overlay. +### 24 is a performance optimization on AMD GPUs that should not have adverse effects on nVidia GPUs. +### A minimum of 20 pixels is recommended by nVidia. +# fcat_overlay_width=24 +### Set the screen edge, this can be useful for special displays that don't update from top edge to bottom. This goes from 0 (left side) to 3 (top edge), counter-clockwise. +# fcat_screen_edge=0 + ### Color customization # text_color=FFFFFF # gpu_color=2E9762 diff --git a/src/fcat.h b/src/fcat.h new file mode 100644 index 00000000..a79045ff --- /dev/null +++ b/src/fcat.h @@ -0,0 +1,63 @@ +#pragma once +#ifndef MANGOHUD_FCAT_H +#define MANGOHUD_FCAT_H + +#include +#include +#include +#include +#include +#include +#include + +#include "timing.hpp" + +#include "overlay_params.h" +#include "overlay.h" + +struct fcatoverlay{ + const struct overlay_params* params = nullptr; + const std::array sequence={{{255, 255, 255},{0, 255, 0},{0, 0, 255},{255, 0, 0},{0, 128, 128},{0, 0, 128},{0, 128, 0},{0, 255, 255},{128, 0, 0},{192, 192, 192},{128, 0, 128},{128, 128, 0},{128, 128, 128},{255, 0, 255},{255, 255, 0},{255, 128, 0}}}; + void update(const struct overlay_params* params_){ + params=params_; + }; + ImColor get_next_color (const swapchain_stats& sw_stats){ + size_t currentColor = sw_stats.n_frames % 16;// should probably be sequence.size(); but this doesn't matter as all FCAT analysis tools use this exact 16 colour sequence. + ImColor output = sequence[currentColor]; + return output; + }; + std::array get_overlay_corners() + { + unsigned short screen_edge=params->fcat_screen_edge; + auto window_size = ImVec2(params->fcat_overlay_width,ImGui::GetIO().DisplaySize.y); + auto p_min = ImVec2(0.,0.); + auto p_max = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y); + //Switch the used screen edge, this enables capture from devices with any screen orientation. + //This goes counter-clockwise from the left edge (0) + switch (screen_edge) + { + default: + case 0: + break; + case 1: + window_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x); + p_min = ImVec2(0,ImGui::GetIO().DisplaySize.y - window_size.y); + p_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y); + break; + case 2: + window_size = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y); + p_min = ImVec2(ImGui::GetIO().DisplaySize.x-window_size.x,0); + p_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y); + break; + case 3: + window_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x); + p_min = ImVec2(0,0); + p_max = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.y); + break; + } + std::array output={{p_min,p_max,window_size}}; + return output; + }; +}; + +#endif diff --git a/src/overlay.cpp b/src/overlay.cpp index 9e1e8e09..05d91a1d 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -14,6 +14,7 @@ #include "gpu.h" #include "memory.h" #include "timing.hpp" +#include "fcat.h" #include "mesa/util/macros.h" #include "battery.h" #include "gamepad.h" @@ -38,6 +39,7 @@ float g_overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */; string gpuString,wineVersion,wineProcess; uint32_t deviceID; bool gui_open = false; +bool fcat_open = false; struct benchmark_stats benchmark; struct fps_limit fps_limit_stats {}; ImVec2 real_font_size; @@ -49,6 +51,7 @@ bool gpu_metrics_exists = false; bool steam_focused = false; vector frametime_data(200,0.f); int fan_speed; +fcatoverlay fcatstatus; void init_spdlog() { @@ -568,6 +571,22 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& if((now - logger->last_log_end()) < 12s && !logger->is_active()) render_benchmark(data, params, window_size, height, now); } + + if(params.enabled[OVERLAY_PARAM_ENABLED_fcat]) + { + fcatstatus.update(¶ms); + auto window_corners = fcatstatus.get_overlay_corners(); + auto p_min=window_corners[0]; + auto p_max=window_corners[1]; + auto window_size= window_corners[2]; + ImGui::SetNextWindowPos(p_min, ImGuiCond_Always); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); + ImGui::SetNextWindowSize(window_size); + ImGui::Begin("FCAT", &fcat_open, ImGuiWindowFlags_NoDecoration| ImGuiWindowFlags_NoBackground); + ImGui::GetWindowDrawList()->AddRectFilled(p_min,p_max,fcatstatus.get_next_color(data),0.0); + ImGui::End(); + ImGui::PopStyleVar(); + } } void init_cpu_stats(overlay_params& params) diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index 0e8e93ec..fdaa8741 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -402,6 +402,8 @@ parse_gl_size_query(const char *str) #define parse_gl_bind_framebuffer(s) parse_unsigned(s) #define parse_gl_dont_flip(s) parse_unsigned(s) != 0 #define parse_round_corners(s) parse_unsigned(s) +#define parse_fcat_overlay_width(s) parse_unsigned(s) +#define parse_fcat_screen_edge(s) parse_unsigned(s) #define parse_cpu_color(s) parse_color(s) #define parse_gpu_color(s) parse_color(s) @@ -578,6 +580,7 @@ parse_overlay_config(struct overlay_params *params, params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery] = false; params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery_icon] = true; params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = false; + params->enabled[OVERLAY_PARAM_ENABLED_fcat] = false; params->fps_sampling_period = 500000000; /* 500ms */ params->width = 0; params->height = 140; @@ -589,6 +592,8 @@ parse_overlay_config(struct overlay_params *params, params->offset_y = 0; params->background_alpha = 0.5; params->alpha = 1.0; + params->fcat_screen_edge = 0; + params->fcat_overlay_width = 24; params->time_format = "%T"; params->gpu_color = 0x2e9762; params->cpu_color = 0x2e97cb; diff --git a/src/overlay_params.h b/src/overlay_params.h index c070e277..7977edfe 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -83,6 +83,7 @@ typedef unsigned long KeySym; OVERLAY_PARAM_BOOL(hide_fsr_sharpness) \ OVERLAY_PARAM_BOOL(fan) \ OVERLAY_PARAM_BOOL(throttling_status) \ + OVERLAY_PARAM_BOOL(fcat) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_file) \ @@ -152,6 +153,8 @@ typedef unsigned long KeySym; OVERLAY_PARAM_CUSTOM(autostart_log) \ OVERLAY_PARAM_CUSTOM(round_corners) \ OVERLAY_PARAM_CUSTOM(fsr_steam_sharpness) \ + OVERLAY_PARAM_CUSTOM(fcat_screen_edge) \ + OVERLAY_PARAM_CUSTOM(fcat_overlay_width) \ enum overlay_param_position { LAYER_POSITION_TOP_LEFT, @@ -252,6 +255,8 @@ struct overlay_params { std::unordered_map options; int permit_upload; int fsr_steam_sharpness; + unsigned short fcat_screen_edge; + unsigned short fcat_overlay_width; size_t font_params_hash; };