diff --git a/src/app/main.cpp b/src/app/main.cpp index 1a6ef3f..0042fbf 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -35,6 +35,8 @@ std::condition_variable mangoapp_cv; static uint8_t raw_msg[1024] = {0}; uint8_t g_fsrUpscale = 0; uint8_t g_fsrSharpness = 0; +std::vector gamescope_debug_latency {}; +std::vector gamescope_debug_app {}; void ctrl_thread(){ while (1){ @@ -74,7 +76,25 @@ void ctrl_thread(){ bool new_frame = false; +void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){ + float app_frametime_ms = app_frametime_ns / 1000000.f; + gamescope_debug_app.push_back(app_frametime_ms); + if (gamescope_debug_app.size() > 200) + gamescope_debug_app.erase(gamescope_debug_app.begin()); + + float latency_ms = latency_ns / 1000000.f; + if (latency_ns == -1) + latency_ms = -1; + gamescope_debug_latency.push_back(latency_ms); + if (gamescope_debug_latency.size() > 200) + gamescope_debug_latency.erase(gamescope_debug_latency.begin()); +} + void msg_read_thread(){ + for (size_t i = 0; i < 200; i++){ + gamescope_debug_app.push_back(0); + gamescope_debug_latency.push_back(0); + } int key = ftok("mangoapp", 65); msgid = msgget(key, 0666 | IPC_CREAT); const struct mangoapp_msg_header *hdr = (const struct mangoapp_msg_header*) raw_msg; @@ -84,12 +104,15 @@ void msg_read_thread(){ // and that we're not trying to use variables that don't exist (yet) size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0); if (hdr->version == 1){ - if (msg_size > offsetof(struct mangoapp_msg_v1, frametime_ns)){ - update_hud_info_with_frametime(sw_stats, *params, vendorID, mangoapp_v1->frametime_ns); + if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){ + update_hud_info_with_frametime(sw_stats, *params, vendorID, mangoapp_v1->visible_frametime_ns); if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){ g_fsrUpscale = mangoapp_v1->fsrUpscale; g_fsrSharpness = mangoapp_v1->fsrSharpness; } + if (msg_size > offsetof(mangoapp_msg_v1, latency_ns)){ + gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns); + } { std::unique_lock lk(mangoapp_m); new_frame = true; diff --git a/src/app/mangoapp.h b/src/app/mangoapp.h index c8c6b28..48334d4 100644 --- a/src/app/mangoapp.h +++ b/src/app/mangoapp.h @@ -3,6 +3,7 @@ #include #include #include +#include extern int ctrl_msgid; extern int msgid; @@ -18,9 +19,12 @@ struct mangoapp_msg_v1 { struct mangoapp_msg_header hdr; uint32_t pid; - uint64_t frametime_ns; + uint64_t visible_frametime_ns; uint8_t fsrUpscale; uint8_t fsrSharpness; + // For debugging + uint64_t app_frametime_ns; + uint64_t latency_ns; // WARNING: Always ADD fields, never remove or repurpose fields } __attribute__((packed)); @@ -42,4 +46,6 @@ struct mangoapp_ctrl_msgid1_v1 { } __attribute__((packed)); extern uint8_t g_fsrUpscale; -extern uint8_t g_fsrSharpness; \ No newline at end of file +extern uint8_t g_fsrSharpness; +extern std::vector gamescope_debug_latency; +extern std::vector gamescope_debug_app; \ No newline at end of file diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index c9afbbb..423d0a9 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -587,7 +587,11 @@ void HudElements::frame_timing(){ ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats, ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, NULL, min_time, max_time, - ImVec2(ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns, 50)); + ImVec2(ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns - 30, 50)); + ImGui::SameLine(); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::Text("%.1fms", frametime / 1000.f); + ImGui::PopFont(); } ImGui::PopStyleColor(); @@ -778,6 +782,68 @@ void HudElements::gamescope_fsr(){ #endif } +void HudElements::gamescope_frame_timing(){ +#ifdef MANGOAPP + if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_debug]) { + ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::TextColored(HUDElements.colors.engine, "%s", "App"); + for (size_t i = 0; i < HUDElements.params->table_columns - 1; i++) + ImGui::TableNextColumn(); + ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); + auto min = std::min_element(gamescope_debug_app.begin(), gamescope_debug_app.end()); + auto max = std::max_element(gamescope_debug_app.begin(), gamescope_debug_app.end()); + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, "min: %.1fms, max: %.1fms", min[0], max[0]); + ImGui::PopFont(); + ImGui::TableNextRow(); ImGui::TableNextColumn(); + char hash[40]; + snprintf(hash, sizeof(hash), "##%s", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]); + HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing; + HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */ + double min_time = 0.0f; + double max_time = 50.0f; + + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::PlotLines("", gamescope_debug_app.data(), + gamescope_debug_app.size(), 0, + NULL, min_time, max_time, + ImVec2(ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns - 30, 50)); + ImGui::SameLine(); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::Text("%.1fms", gamescope_debug_app.back()); + ImGui::PopFont(); + ImGui::PopStyleColor(); + if (gamescope_debug_latency.back() > -1){ + ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::TextColored(HUDElements.colors.engine, "%s", "Latency"); + for (size_t i = 0; i < HUDElements.params->table_columns - 1; i++) + ImGui::TableNextColumn(); + ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); + min = std::min_element(gamescope_debug_latency.begin(), gamescope_debug_latency.end()); + max = std::max_element(gamescope_debug_latency.begin(), gamescope_debug_latency.end()); + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, "min: %.1fms, max: %.1fms", min[0], max[0]); + ImGui::PopFont(); + ImGui::TableNextRow(); ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(0,0,1,1)); + ImGui::PlotLines("", gamescope_debug_latency.data(), + gamescope_debug_latency.size(), 0, + NULL, min_time, max_time, + ImVec2(ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns - 30, 50)); + ImGui::SameLine(); + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::Text("%.1fms", gamescope_debug_latency.back()); + ImGui::PopFont(); + ImGui::PopStyleColor(2); + } + } +#endif +} + void HudElements::graphs(){ ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); @@ -928,6 +994,7 @@ void HudElements::sort_elements(const std::pair& optio if (param == "battery") { ordered_functions.push_back({battery, value}); } if (param == "fps_only") { ordered_functions.push_back({fps_only, value}); } if (param == "fsr") { ordered_functions.push_back({gamescope_fsr, value}); } + if (param == "debug") { ordered_functions.push_back({gamescope_frame_timing, value}); } if (param == "graphs"){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs]) HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs] = true; @@ -971,6 +1038,7 @@ void HudElements::legacy_elements(){ ordered_functions.push_back({wine, value}); #endif ordered_functions.push_back({frame_timing, value}); + ordered_functions.push_back({gamescope_frame_timing, value}); #ifndef MANGOAPP ordered_functions.push_back({gamemode, value}); ordered_functions.push_back({vkbasalt, value}); diff --git a/src/hud_elements.h b/src/hud_elements.h index 75c2f19..3215b72 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -60,6 +60,7 @@ class HudElements{ static void battery(); static void fps_only(); static void gamescope_fsr(); + static void gamescope_frame_timing(); void convert_colors(struct overlay_params& params); void convert_colors(bool do_conv, struct overlay_params& params); diff --git a/src/overlay_params.h b/src/overlay_params.h index 4d4a9b2..72c20d0 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -76,6 +76,7 @@ typedef unsigned long KeySym; OVERLAY_PARAM_BOOL(force_amdgpu_hwmon) \ OVERLAY_PARAM_BOOL(fps_only) \ OVERLAY_PARAM_BOOL(fsr) \ + OVERLAY_PARAM_BOOL(debug) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_file) \