36#include "table/strings.h"
40static std::mutex _sound_perf_lock;
41static std::atomic<bool> _sound_perf_pending;
42static std::vector<TimingMeasurement> _sound_perf_measurements;
59 std::array<TimingMeasurement, NUM_FRAMERATE_POINTS>
durations{};
61 std::array<TimingMeasurement, NUM_FRAMERATE_POINTS>
timestamps{};
91 this->durations[this->next_index] = end_time - start_time;
92 this->timestamps[this->next_index] = start_time;
93 this->prev_index = this->next_index;
94 this->next_index += 1;
105 this->timestamps[this->next_index] = this->acc_timestamp;
106 this->durations[this->next_index] = this->acc_duration;
107 this->prev_index = this->next_index;
108 this->next_index += 1;
112 this->acc_duration = 0;
113 this->acc_timestamp = start_time;
122 this->acc_duration += duration;
132 this->timestamps[this->next_index] = start_time;
134 this->prev_index = this->next_index;
135 this->next_index += 1;
137 this->num_valid += 1;
148 count = std::min(count, this->num_valid);
150 int first_point = this->prev_index - count;
155 const int last_point = first_point + count;
156 for (
int i = first_point; i < last_point; i++) {
166 if (count == 0)
return 0;
177 int point = this->prev_index;
178 int last_point = this->next_index - this->num_valid;
192 while (point != last_point) {
195 total += last - this->timestamps[point];
198 last = this->timestamps[point];
204 if (total == 0 || count == 0)
return 0;
260 using namespace std::chrono;
261 return (
TimingMeasurement)time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count();
296 std::lock_guard lk(_sound_perf_lock);
297 if (_sound_perf_measurements.size() >= NUM_FRAMERATE_POINTS * 2)
return;
298 _sound_perf_measurements.push_back(this->start_time);
299 _sound_perf_measurements.push_back(end);
300 _sound_perf_pending.store(
true, std::memory_order_release);
312 _pf_data[this->elem].expected_rate = rate;
321 _pf_data[elem].num_valid = 0;
322 _pf_data[elem].next_index = 0;
323 _pf_data[elem].prev_index = 0;
425static constexpr std::initializer_list<NWidgetPart> _framerate_window_widgets = {
460 int num_displayed = 0;
466 inline void SetRate(
double value,
double target)
468 const double threshold_good = target * 0.95;
469 const double threshold_bad = target * 2 / 3;
470 this->value = (uint32_t)(value * 100);
471 this->strid = (value > threshold_good) ? STR_FRAMERATE_FPS_GOOD : (value < threshold_bad) ? STR_FRAMERATE_FPS_BAD : STR_FRAMERATE_FPS_WARN;
474 inline void SetTime(
double value,
double target)
476 const double threshold_good = target / 3;
477 const double threshold_bad = target;
478 this->value = (uint32_t)(value * 100);
479 this->strid = (value < threshold_good) ? STR_FRAMERATE_MS_GOOD : (value > threshold_bad) ? STR_FRAMERATE_MS_BAD : STR_FRAMERATE_MS_WARN;
482 inline uint32_t GetValue()
const {
return this->value; }
483 inline uint32_t GetDecimals()
const {
return 2; }
499 this->num_displayed = this->num_active;
529 if (new_active != this->num_active) {
530 this->num_active = new_active;
533 sb->
SetCapacity(std::min(this->num_displayed, this->num_active));
540 case WID_FRW_CAPTION:
544 return GetString(STR_FRAMERATE_CAPTION_SMALL, this->rate_gameloop.strid, this->rate_gameloop.GetValue(), this->rate_gameloop.GetDecimals(), this->speed_gameloop.GetValue(), this->speed_gameloop.GetDecimals());
546 case WID_FRW_RATE_GAMELOOP:
547 return GetString(STR_FRAMERATE_RATE_GAMELOOP, this->rate_gameloop.strid, this->rate_gameloop.GetValue(), this->rate_gameloop.GetDecimals());
549 case WID_FRW_RATE_DRAWING:
550 return GetString(STR_FRAMERATE_RATE_BLITTER, this->rate_drawing.strid, this->rate_drawing.GetValue(), this->rate_drawing.GetDecimals());
552 case WID_FRW_RATE_FACTOR:
553 return GetString(STR_FRAMERATE_SPEED_FACTOR, this->speed_gameloop.GetValue(), this->speed_gameloop.GetDecimals());
555 case WID_FRW_INFO_DATA_POINTS:
566 case WID_FRW_RATE_GAMELOOP:
569 case WID_FRW_RATE_DRAWING:
572 case WID_FRW_RATE_FACTOR:
576 case WID_FRW_TIMES_NAMES: {
582 if (
_pf_data[e].num_valid == 0)
continue;
589 size.width = std::max(size.width, line_size.width);
594 case WID_FRW_TIMES_CURRENT:
595 case WID_FRW_TIMES_AVERAGE:
596 case WID_FRW_ALLOCSIZE: {
599 size.width = std::max(size.width, item_size.width);
618 int drawable = this->num_displayed;
623 if (
_pf_data[e].num_valid == 0)
continue;
630 if (drawable == 0)
break;
635 void DrawElementAllocationsColumn(
const Rect &r)
const
639 int drawable = this->num_displayed;
644 if (
_pf_data[e].num_valid == 0)
continue;
652 if (drawable == 0)
break;
657 if (drawable == 0)
break;
662 if (drawable == 0)
break;
670 case WID_FRW_TIMES_NAMES: {
674 int drawable = this->num_displayed;
677 if (
_pf_data[e].num_valid == 0)
continue;
688 if (drawable == 0)
break;
693 case WID_FRW_TIMES_CURRENT:
697 case WID_FRW_TIMES_AVERAGE:
701 case WID_FRW_ALLOCSIZE:
702 DrawElementAllocationsColumn(r);
710 case WID_FRW_TIMES_NAMES:
711 case WID_FRW_TIMES_CURRENT:
712 case WID_FRW_TIMES_AVERAGE: {
716 if (line != INT32_MAX) {
720 if (
_pf_data[e].num_valid > 0) line--;
743 WindowClass::FramerateDisplay, WindowClass::None,
745 _framerate_window_widgets
750static constexpr std::initializer_list<NWidgetPart> _frametime_graph_window_widgets = {
779 case WID_FGW_CAPTION:
792 if (widget == WID_FGW_GRAPH) {
818 static const std::initializer_list<ScaleDef> hscales = {
825 for (
const auto &sc : hscales) {
833 static const std::initializer_list<TimingMeasurement> vscales = {
844 for (
const auto &sc : vscales) {
852 const auto &durations =
_pf_data[this->element].durations;
853 const auto ×tamps =
_pf_data[this->element].timestamps;
854 int num_valid =
_pf_data[this->element].num_valid;
855 int point =
_pf_data[this->element].prev_index;
863 this->horizontal_scale = 4;
865 for (
int i = 1; i < num_valid; i++) {
872 lastts = timestamps[point];
875 if (value > peak_value) peak_value = value;
879 time_sum += lastts - timestamps[point];
880 lastts = timestamps[point];
883 if (count == 60) this->SelectHorizontalScale(time_sum);
886 if (count >= 60 && time_sum >= (this->horizontal_scale + 2) *
TIMESTAMP_PRECISION / 2)
break;
889 this->SelectVerticalScale(peak_value);
911 template <
typename T>
914 T dst_diff = dst_max - dst_min;
915 T src_diff = src_max - src_min;
916 return (value - src_min) * dst_diff / src_diff + dst_min;
921 if (widget == WID_FGW_GRAPH) {
922 const auto &durations =
_pf_data[this->element].durations;
923 const auto ×tamps =
_pf_data[this->element].timestamps;
924 int point =
_pf_data[this->element].prev_index;
926 const int x_zero = r.right - (int)this->graph_size.width;
927 const int x_max = r.right;
928 const int y_zero = r.top + (int)this->graph_size.height;
929 const int y_max = r.top;
938 const uint horz_div_scl = (this->horizontal_scale <= 20) ? 1 : 10;
940 const uint horz_divisions = this->horizontal_scale / horz_div_scl;
942 const uint vert_divisions = 10;
945 for (uint division = 0; division < vert_divisions; division++) {
946 int y =
Scinterlate(y_zero, y_max, 0, (
int)vert_divisions, (
int)division);
947 GfxDrawLine(x_zero, y, x_max, y, c_grid);
948 if (division % 2 == 0) {
961 for (uint division = horz_divisions; division > 0; division--) {
962 int x =
Scinterlate(x_zero, x_max, 0, (
int)horz_divisions, (
int)horz_divisions - (
int)division);
963 GfxDrawLine(x, y_max, x, y_zero, c_grid);
964 if (division % 2 == 0) {
966 GetString(STR_FRAMERATE_GRAPH_SECONDS, division * horz_div_scl / 2),
980 Point peak_point = { 0, 0 };
983 int points_drawn = 0;
992 lastts = timestamps[point];
997 time_sum += lastts - timestamps[point];
998 lastts = timestamps[point];
1000 if (time_sum > draw_horz_scale)
break;
1004 (int)
Scinterlate<int64_t>(x_zero, x_max, 0, (int64_t)draw_horz_scale, (int64_t)draw_horz_scale - (int64_t)time_sum),
1007 if (newpoint.
x > lastpoint.
x)
continue;
1008 GfxDrawLine(lastpoint.
x, lastpoint.
y, newpoint.
x, newpoint.
y, c_lines);
1009 lastpoint = newpoint;
1014 if (value > peak_value) {
1016 peak_point = newpoint;
1021 if (points_drawn > 0 && peak_value >
TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) {
1023 GfxFillRect(peak_point.
x - 1, peak_point.
y - 1, peak_point.
x + 1, peak_point.
y + 1, c_peak);
1026 if (peak_point.
x - x_zero > (
int)this->graph_size.width / 2) {
1039 WindowClass::FrametimeGraph, WindowClass::None,
1041 _frametime_graph_window_widgets
1073 " GL station ticks",
1075 " GL road vehicle ticks",
1077 " GL aircraft ticks",
1078 " GL landscape ticks",
1079 " GL link graph delays",
1081 " Viewport drawing",
1084 "AI/GS scripts total",
1087 std::string ai_name_buf;
1089 bool printed_anything =
false;
1093 if (pf.num_valid == 0)
continue;
1095 MEASUREMENT_NAMES[e],
1098 printed_anything =
true;
1103 if (pf.num_valid == 0)
continue;
1104 std::string_view name;
1106 name = MEASUREMENT_NAMES[e];
1113 pf.GetAverageDurationMilliseconds(count1),
1114 pf.GetAverageDurationMilliseconds(count2),
1115 pf.GetAverageDurationMilliseconds(count3));
1116 printed_anything =
true;
1119 if (!printed_anything) {
1133 if (_sound_perf_pending.load(std::memory_order_acquire)) {
1134 std::lock_guard lk(_sound_perf_lock);
1135 for (
size_t i = 0; i < _sound_perf_measurements.size(); i += 2) {
1138 _sound_perf_measurements.clear();
1139 _sound_perf_pending.store(
false, std::memory_order_relaxed);
AIInfo keeps track of all information of an AI, like Author, Description, ...
The AIInstance tracks an AI.
Iterate a range of enum values.
static class GameInstance * GetInstance()
Get the current active instance.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition of stuff that is very close to a company, like the company struct itself.
void IConsolePrint(ExtendedTextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Console functions used outside of the console code.
Globally used console related types.
static const TextColour CC_ERROR
Colour for error lines.
#define T
Climate temperate.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
void ShowFramerateWindow()
Open the general framerate window.
static WindowDesc _framerate_display_desc(WindowPosition::Automatic, "framerate_display", 0, 0, WindowClass::FramerateDisplay, WindowClass::None, {}, _framerate_window_widgets)
Window definition for the frame rate window.
static TimingMeasurement GetPerformanceTimer()
Return a timestamp with TIMESTAMP_PRECISION ticks per second precision.
void ProcessPendingPerformanceMeasurements()
This drains the PerformanceElement::Sound measurement data queue into _pf_data.
void ShowFrametimeGraphWindow(PerformanceElement elem)
Open a graph window for a performance element.
static constexpr CompanyID GetAIIndex(PerformanceElement e)
Get the CompanyID associated with the AI of the given PerformanceElement.
void ConPrintFramerate()
Print performance statistics to game console.
static WindowDesc _frametime_graph_window_desc(WindowPosition::Automatic, "frametime_graph", 140, 90, WindowClass::FrametimeGraph, WindowClass::None, {}, _frametime_graph_window_widgets)
Window definition for the frame rate graph window.
static std::string_view GetAIName(PerformanceElement e)
Get the name of the AI of the given PerformanceElement.
static constexpr EnumIndexArray< PerformanceElement, PerformanceElement, PerformanceElement::End > DISPLAY_ORDER_PFE
Order of the performance elements in the user interface.
Types for recording game performance data.
PerformanceElement
Elements of game performance that can be measured.
@ AI7
AI execution for player slot 8.
@ GameLoopLandscape
Time spent processing other world features.
@ AI0
AI execution for player slot 1.
@ Video
Speed of painting drawn video buffer.
@ GameLoopRoadVehicles
Time spend processing road vehicles.
@ GameLoop
Speed of gameloop processing.
@ GameLoopShips
Time spent processing ships.
@ AI9
AI execution for player slot 10.
@ Drawing
Speed of drawing world and GUI.
@ AllScripts
Sum of all GS/AI scripts.
@ GameLoopAircraft
Time spent processing aircraft.
@ End
End of enum, must be last.
@ AI11
AI execution for player slot 12.
@ GameScript
Game script execution.
@ AI4
AI execution for player slot 5.
@ GameLoopTrains
Time spent processing trains.
@ Sound
Speed of mixing audio samples.
@ AI10
AI execution for player slot 11.
@ AI12
AI execution for player slot 13.
@ GameLoopEconomy
Time spent processing cargo movement.
@ AI3
AI execution for player slot 4.
@ ViewportDrawing
Time spent drawing world viewports in GUI.
@ AI13
AI execution for player slot 14.
@ AI5
AI execution for player slot 6.
@ AI14
AI execution for player slot 15.
@ GameLoopLinkGraph
Time spent waiting for link graph background jobs.
@ AI8
AI execution for player slot 9.
@ AI2
AI execution for player slot 3.
@ AI6
AI execution for player slot 7.
@ AI1
AI execution for player slot 2.
uint64_t TimingMeasurement
Type used to hold a performance timing measurement.
Base functions for all Games.
The GameInstance tracks games.
@ ForceRight
Force align to the right.
@ Start
Align to the start, LTR/RTL aware.
@ ForceLeft
Force align to the left.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
int DrawString(int left, int right, int top, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Functions related to the gfx engine.
@ Small
Index of the small font in the font tables.
@ Normal
Index of the normal font in the font tables.
@ LightBlue
Light blue colour.
@ FromString
Marker for telling to use the colour from the string.
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
const TimingMeasurement TIMESTAMP_PRECISION
Units a second is divided into in performance measurements
static const double GL_RATE
Game loop rate, cycles per second
const int NUM_FRAMERATE_POINTS
Number of data points to keep in buffer for each performance measurement.
static EnumIndexArray< PerformanceData, PerformanceElement, PerformanceElement::End > _pf_data
Storage for all performance element measurements.
size_t GetSoundPoolAllocatedMemory()
Get size of memory allocated to sound effects.
Functions related to NewGRF provided sounds.
static constexpr PixelColour PC_DARK_RED
Dark red palette colour.
static constexpr PixelColour PC_DARK_GREY
Dark grey palette colour.
static constexpr PixelColour PC_BLACK
Black palette colour.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static bool IsValidAiID(auto index)
Is this company a valid company, controlled by the computer (a NoAI program)?
Dimensions (a width and height) of a rectangle in 2D.
Container for the text colour and some text colour related flags for drawing.
void OnResize() override
Called after the window got resized.
void DrawElementTimesColumn(const Rect &r, StringID heading_str, const CachedDecimalArray &values) const
Render a column of formatted average durations.
CachedDecimal rate_drawing
cached drawing frame rate
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
EnumIndexArray< CachedDecimal, PerformanceElement, PerformanceElement::End > CachedDecimalArray
Array of cached decimals.
CachedDecimalArray times_shortterm
cached short term average times
CachedDecimalArray times_longterm
cached long term average times
CachedDecimal speed_gameloop
cached game loop speed factor
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
const IntervalTimer< TimerWindow > update_interval
Update the window on a regular interval.
CachedDecimal rate_gameloop
cached game loop tick rate
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static constexpr int MIN_ELEMENTS
smallest number of elements to display
int horizontal_scale
number of half-second units horizontally
void OnRealtimeTick(uint delta_ms) override
Called periodically.
void UpdateScale()
Recalculate the graph scaling factors based on current recorded data.
const IntervalTimer< TimerWindow > update_interval
Update the scaling on a regular interval.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Dimension graph_size
size of the main graph area (excluding axis labels)
PerformanceElement element
what element this window renders graph for
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
static T Scinterlate(T dst_min, T dst_max, T src_min, T src_max, T value)
Scale and interpolate a value from a source range into a destination range.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
int vertical_scale
number of TIMESTAMP_PRECISION units vertically
Colour for pixel/line drawing.
static Company * Get(auto index)
Specification of a rectangle with absolute coordinates of all edges.
High level window description.
Number to differentiate different windows of the same class.
Data structure for an opened window.
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
ResizeInfo resize
Resize information.
bool IsShaded() const
Is window shaded currently?
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition of Interval and OneShot timers.
Definition of the Window system.
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ Automatic
Find a place automatically.
Functions related to zooming.