The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
fps_report.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2025 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15#define GETTEXT_DOMAIN "wesnoth-lib"
16
18
19#include "filesystem.hpp"
25
26#include <tuple>
27#include <vector>
28
29#ifdef DUMP_FPS_TO_FILE
30#undef DUMP_FPS_TO_FILE
31#endif
32
33namespace gui2::dialogs
34{
35namespace
36{
37class fps_report : public modeless_dialog
38{
39public:
40 fps_report(const gui2::tracked_drawable& target)
41 : modeless_dialog(window_id())
42 , target_(target)
43 {
44 }
45
46private:
47 const std::string& window_id() const override;
48
49 /* Inherited from top_level_drawable. */
50 void update() override;
51
52 /** The drawable whose render calls we are tracking. */
54
55 /** Only update the displayed count every few update cycles. */
57
58 /** Holds the prior (max 1000) displayed fps values. */
59 std::vector<std::tuple<int, int, int>> fps_history_{};
60};
61
62/** Generates the rich_label markup for the report. */
63auto generate_markup(const gui2::tracked_drawable::frame_info& info)
64{
65 return config{ "table", config{ "width", "fill",
66 "row", config{
67 "col", config{},
68 "col", config{ "halign", "right", "text", "min" },
69 "col", config{ "halign", "right", "text", "avg" },
70 "col", config{ "halign", "right", "text", "max" },
71 "col", config{ "halign", "right", "text", "act" },
72 },
73
74 "row", config{
75 "col", config{ "halign", "right", "text", "fps" },
76 "col", config{ "halign", "right", "text", info.min_fps },
77 "col", config{ "halign", "right", "text", info.avg_fps },
78 "col", config{ "halign", "right", "text", info.max_fps },
79 "col", config{ "halign", "right", "text", info.act_fps },
80 },
81
82 "row", config{
83 "col", config{ "halign", "right", "text", "ms" },
84 "col", config{ "halign", "right", "text", info.max_time },
85 "col", config{ "halign", "right", "text", info.avg_time },
86 "col", config{ "halign", "right", "text", info.min_time },
87 "col", config{},
88 },
89 }};
90}
91
92void fps_report::update()
93{
94 if(!update_check_.poll()) {
95 return;
96 }
97
98 // Will be null if no times have been recorded yet
99 auto info = target_.get_info();
100 if(!info) {
101 return;
102 }
103
104 find_widget<rich_label>("values").set_dom(generate_markup(*info));
105
106#ifdef DUMP_FPS_TO_FILE
107 fps_history_.emplace_back(info->min_fps, info->avg_fps, info->max_fps);
108
109 // Flush out the stored values every so often
110 if(fps_history_.size() == 1000) {
111 std::string filename = filesystem::get_user_data_dir() + "/fps_log.csv";
112 auto fps_log = filesystem::ostream_file(filename, std::ios_base::binary | std::ios_base::app);
113
114 for(const auto& [min, avg, max] : fps_history_) {
115 *fps_log << min << "," << avg << "," << max << "\n";
116 }
117
118 fps_history_.clear();
119 }
120#endif
121}
122
123std::unique_ptr<fps_report> report;
124
125} // namespace
126
127REGISTER_DIALOG(fps_report)
128
129namespace fps
130{
131void show(const gui2::tracked_drawable& target)
132{
133 // No-op if currently displayed
134 if(report) {
135 return;
136 }
137
138 report.reset(new fps_report(target));
139 report->show();
140
141 // HACK: in order that the display not prevent events from reaching the in-game
142 // event context, leave the UI event context. This should be removed if ever we
143 // get the two event contexts to play nicely...
144 report->disconnect();
145}
146
147void hide()
148{
149 report.reset();
150}
151
152} // namespace fps
153
154} // namespace gui2::dialogs
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
Middleware class that tracks framerate and times.
auto get_info() const -> utils::optional< frame_info >
Returns the current frame time and info, or nullopt if no times have been recorded.
bool poll()
Checks whether the counter is now a multiple of the chosen rate, then increments it by one.
Declarations for File-IO.
utils::rate_counter update_check_
Only update the displayed count every few update cycles.
const gui2::tracked_drawable & target_
The drawable whose render calls we are tracking.
std::vector< std::tuple< int, int, int > > fps_history_
Holds the prior (max 1000) displayed fps values.
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
std::string get_user_data_dir()
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode=std::ios_base::binary, bool create_directory=true)
void hide()
Hides the fps report popup.
logger & info()
Definition log.cpp:351
std::string filename
Filename.