OpenTTD Source  1.11.0-beta2
framerate_gui.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7 
10 #include "framerate_type.h"
11 #include <chrono>
12 #include "gfx_func.h"
13 #include "window_gui.h"
14 #include "window_func.h"
15 #include "table/sprites.h"
16 #include "string_func.h"
17 #include "strings_func.h"
18 #include "console_func.h"
19 #include "console_type.h"
20 #include "guitimer_func.h"
21 #include "company_base.h"
22 #include "ai/ai_info.hpp"
23 #include "ai/ai_instance.hpp"
24 #include "game/game.hpp"
25 #include "game/game_instance.hpp"
26 
28 #include "safeguards.h"
29 
30 
34 namespace {
35 
37  const int NUM_FRAMERATE_POINTS = 512;
40 
41  struct PerformanceData {
43  static const TimingMeasurement INVALID_DURATION = UINT64_MAX;
44 
50  double expected_rate;
56  int num_valid;
57 
62 
69  explicit PerformanceData(double expected_rate) : expected_rate(expected_rate), next_index(0), prev_index(0), num_valid(0) { }
70 
72  void Add(TimingMeasurement start_time, TimingMeasurement end_time)
73  {
74  this->durations[this->next_index] = end_time - start_time;
75  this->timestamps[this->next_index] = start_time;
76  this->prev_index = this->next_index;
77  this->next_index += 1;
78  if (this->next_index >= NUM_FRAMERATE_POINTS) this->next_index = 0;
79  this->num_valid = std::min(NUM_FRAMERATE_POINTS, this->num_valid + 1);
80  }
81 
84  {
85  this->timestamps[this->next_index] = this->acc_timestamp;
86  this->durations[this->next_index] = this->acc_duration;
87  this->prev_index = this->next_index;
88  this->next_index += 1;
89  if (this->next_index >= NUM_FRAMERATE_POINTS) this->next_index = 0;
90  this->num_valid = std::min(NUM_FRAMERATE_POINTS, this->num_valid + 1);
91 
92  this->acc_duration = 0;
93  this->acc_timestamp = start_time;
94  }
95 
98  {
99  this->acc_duration += duration;
100  }
101 
103  void AddPause(TimingMeasurement start_time)
104  {
105  if (this->durations[this->prev_index] != INVALID_DURATION) {
106  this->timestamps[this->next_index] = start_time;
107  this->durations[this->next_index] = INVALID_DURATION;
108  this->prev_index = this->next_index;
109  this->next_index += 1;
110  if (this->next_index >= NUM_FRAMERATE_POINTS) this->next_index = 0;
111  this->num_valid += 1;
112  }
113  }
114 
117  {
118  count = std::min(count, this->num_valid);
119 
120  int first_point = this->prev_index - count;
121  if (first_point < 0) first_point += NUM_FRAMERATE_POINTS;
122 
123  /* Sum durations, skipping invalid points */
124  double sumtime = 0;
125  for (int i = first_point; i < first_point + count; i++) {
126  auto d = this->durations[i % NUM_FRAMERATE_POINTS];
127  if (d != INVALID_DURATION) {
128  sumtime += d;
129  } else {
130  /* Don't count the invalid durations */
131  count--;
132  }
133  }
134 
135  if (count == 0) return 0; // avoid div by zero
136  return sumtime * 1000 / count / TIMESTAMP_PRECISION;
137  }
138 
140  double GetRate()
141  {
142  /* Start at last recorded point, end at latest when reaching the earliest recorded point */
143  int point = this->prev_index;
144  int last_point = this->next_index - this->num_valid;
145  if (last_point < 0) last_point += NUM_FRAMERATE_POINTS;
146 
147  /* Number of data points collected */
148  int count = 0;
149  /* Time of previous data point */
150  TimingMeasurement last = this->timestamps[point];
151  /* Total duration covered by collected points */
152  TimingMeasurement total = 0;
153 
154  /* We have nothing to compare the first point against */
155  point--;
156  if (point < 0) point = NUM_FRAMERATE_POINTS - 1;
157 
158  while (point != last_point) {
159  /* Only record valid data points, but pretend the gaps in measurements aren't there */
160  if (this->durations[point] != INVALID_DURATION) {
161  total += last - this->timestamps[point];
162  count++;
163  }
164  last = this->timestamps[point];
165  if (total >= TIMESTAMP_PRECISION) break; // end after 1 second has been collected
166  point--;
167  if (point < 0) point = NUM_FRAMERATE_POINTS - 1;
168  }
169 
170  if (total == 0 || count == 0) return 0;
171  return (double)count * TIMESTAMP_PRECISION / total;
172  }
173  };
174 
176  static const double GL_RATE = 1000.0 / MILLISECONDS_PER_TICK;
177 
184  PerformanceData(GL_RATE), // PFE_GAMELOOP
185  PerformanceData(1), // PFE_ACC_GL_ECONOMY
186  PerformanceData(1), // PFE_ACC_GL_TRAINS
187  PerformanceData(1), // PFE_ACC_GL_ROADVEHS
188  PerformanceData(1), // PFE_ACC_GL_SHIPS
189  PerformanceData(1), // PFE_ACC_GL_AIRCRAFT
190  PerformanceData(1), // PFE_GL_LANDSCAPE
191  PerformanceData(1), // PFE_GL_LINKGRAPH
192  PerformanceData(1000.0 / 30), // PFE_DRAWING
193  PerformanceData(1), // PFE_ACC_DRAWWORLD
194  PerformanceData(60.0), // PFE_VIDEO
195  PerformanceData(1000.0 * 8192 / 44100), // PFE_SOUND
196  PerformanceData(1), // PFE_ALLSCRIPTS
197  PerformanceData(1), // PFE_GAMESCRIPT
198  PerformanceData(1), // PFE_AI0 ...
199  PerformanceData(1),
200  PerformanceData(1),
201  PerformanceData(1),
202  PerformanceData(1),
203  PerformanceData(1),
204  PerformanceData(1),
205  PerformanceData(1),
206  PerformanceData(1),
207  PerformanceData(1),
208  PerformanceData(1),
209  PerformanceData(1),
210  PerformanceData(1),
211  PerformanceData(1),
212  PerformanceData(1), // PFE_AI14
213  };
214 
215 }
216 
217 
224 {
225  using namespace std::chrono;
226  return (TimingMeasurement)time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count();
227 }
228 
229 
235 {
236  assert(elem < PFE_MAX);
237 
238  this->elem = elem;
239  this->start_time = GetPerformanceTimer();
240 }
241 
244 {
245  if (this->elem == PFE_ALLSCRIPTS) {
246  /* Hack to not record scripts total when no scripts are active */
247  bool any_active = _pf_data[PFE_GAMESCRIPT].num_valid > 0;
248  for (uint e = PFE_AI0; e < PFE_MAX; e++) any_active |= _pf_data[e].num_valid > 0;
249  if (!any_active) {
251  return;
252  }
253  }
254  _pf_data[this->elem].Add(this->start_time, GetPerformanceTimer());
255 }
256 
259 {
260  _pf_data[this->elem].expected_rate = rate;
261 }
262 
265 {
266  _pf_data[elem].num_valid = 0;
267  _pf_data[elem].next_index = 0;
268  _pf_data[elem].prev_index = 0;
269 }
270 
276 {
278 }
279 
280 
286 {
287  assert(elem < PFE_MAX);
288 
289  this->elem = elem;
290  this->start_time = GetPerformanceTimer();
291 }
292 
295 {
296  _pf_data[this->elem].AddAccumulate(GetPerformanceTimer() - this->start_time);
297 }
298 
305 {
307 }
308 
309 
311 
312 
313 static const PerformanceElement DISPLAY_ORDER_PFE[PFE_MAX] = {
314  PFE_GAMELOOP,
318  PFE_GL_SHIPS,
323  PFE_AI0,
324  PFE_AI1,
325  PFE_AI2,
326  PFE_AI3,
327  PFE_AI4,
328  PFE_AI5,
329  PFE_AI6,
330  PFE_AI7,
331  PFE_AI8,
332  PFE_AI9,
333  PFE_AI10,
334  PFE_AI11,
335  PFE_AI12,
336  PFE_AI13,
337  PFE_AI14,
339  PFE_DRAWING,
341  PFE_VIDEO,
342  PFE_SOUND,
343 };
344 
345 static const char * GetAIName(int ai_index)
346 {
347  if (!Company::IsValidAiID(ai_index)) return "";
348  return Company::Get(ai_index)->ai_info->GetName();
349 }
350 
352 static const NWidgetPart _framerate_window_widgets[] = {
354  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
355  NWidget(WWT_CAPTION, COLOUR_GREY, WID_FRW_CAPTION), SetDataTip(STR_FRAMERATE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
356  NWidget(WWT_SHADEBOX, COLOUR_GREY),
357  NWidget(WWT_STICKYBOX, COLOUR_GREY),
358  EndContainer(),
359  NWidget(WWT_PANEL, COLOUR_GREY),
360  NWidget(NWID_VERTICAL), SetPadding(6), SetPIP(0, 3, 0),
361  NWidget(WWT_TEXT, COLOUR_GREY, WID_FRW_RATE_GAMELOOP), SetDataTip(STR_FRAMERATE_RATE_GAMELOOP, STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP),
362  NWidget(WWT_TEXT, COLOUR_GREY, WID_FRW_RATE_DRAWING), SetDataTip(STR_FRAMERATE_RATE_BLITTER, STR_FRAMERATE_RATE_BLITTER_TOOLTIP),
363  NWidget(WWT_TEXT, COLOUR_GREY, WID_FRW_RATE_FACTOR), SetDataTip(STR_FRAMERATE_SPEED_FACTOR, STR_FRAMERATE_SPEED_FACTOR_TOOLTIP),
364  EndContainer(),
365  EndContainer(),
367  NWidget(WWT_PANEL, COLOUR_GREY),
368  NWidget(NWID_VERTICAL), SetPadding(6), SetPIP(0, 3, 0),
369  NWidget(NWID_HORIZONTAL), SetPIP(0, 6, 0),
370  NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_NAMES), SetScrollbar(WID_FRW_SCROLLBAR),
371  NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_CURRENT), SetScrollbar(WID_FRW_SCROLLBAR),
372  NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_AVERAGE), SetScrollbar(WID_FRW_SCROLLBAR),
373  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_FRW_SEL_MEMORY),
374  NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_ALLOCSIZE), SetScrollbar(WID_FRW_SCROLLBAR),
375  EndContainer(),
376  EndContainer(),
377  NWidget(WWT_TEXT, COLOUR_GREY, WID_FRW_INFO_DATA_POINTS), SetDataTip(STR_FRAMERATE_DATA_POINTS, 0x0),
378  EndContainer(),
379  EndContainer(),
381  NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_FRW_SCROLLBAR),
382  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
383  EndContainer(),
384  EndContainer(),
385 };
386 
388  bool small;
389  bool showing_memory;
390  GUITimer next_update;
391  int num_active;
392  int num_displayed;
393 
394  struct CachedDecimal {
395  StringID strid;
396  uint32 value;
397 
398  inline void SetRate(double value, double target)
399  {
400  const double threshold_good = target * 0.95;
401  const double threshold_bad = target * 2 / 3;
402  value = std::min(9999.99, value);
403  this->value = (uint32)(value * 100);
404  this->strid = (value > threshold_good) ? STR_FRAMERATE_FPS_GOOD : (value < threshold_bad) ? STR_FRAMERATE_FPS_BAD : STR_FRAMERATE_FPS_WARN;
405  }
406 
407  inline void SetTime(double value, double target)
408  {
409  const double threshold_good = target / 3;
410  const double threshold_bad = target;
411  value = std::min(9999.99, value);
412  this->value = (uint32)(value * 100);
413  this->strid = (value < threshold_good) ? STR_FRAMERATE_MS_GOOD : (value > threshold_bad) ? STR_FRAMERATE_MS_BAD : STR_FRAMERATE_MS_WARN;
414  }
415 
416  inline void InsertDParams(uint n) const
417  {
418  SetDParam(n, this->value);
419  SetDParam(n + 1, 2);
420  }
421  };
422 
428 
429  static constexpr int VSPACING = 3;
430  static constexpr int MIN_ELEMENTS = 5;
431 
432  FramerateWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
433  {
434  this->InitNested(number);
435  this->small = this->IsShaded();
436  this->showing_memory = true;
437  this->UpdateData();
438  this->num_displayed = this->num_active;
439  this->next_update.SetInterval(100);
440 
441  /* Window is always initialised to MIN_ELEMENTS height, resize to contain num_displayed */
442  ResizeWindow(this, 0, (std::max(MIN_ELEMENTS, this->num_displayed) - MIN_ELEMENTS) * FONT_HEIGHT_NORMAL);
443  }
444 
445  void OnRealtimeTick(uint delta_ms) override
446  {
447  bool elapsed = this->next_update.Elapsed(delta_ms);
448 
449  /* Check if the shaded state has changed, switch caption text if it has */
450  if (this->small != this->IsShaded()) {
451  this->small = this->IsShaded();
452  this->GetWidget<NWidgetLeaf>(WID_FRW_CAPTION)->SetDataTip(this->small ? STR_FRAMERATE_CAPTION_SMALL : STR_FRAMERATE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
453  elapsed = true;
454  }
455 
456  if (elapsed) {
457  this->UpdateData();
458  this->SetDirty();
459  this->next_update.SetInterval(100);
460  }
461  }
462 
463  void UpdateData()
464  {
465  double gl_rate = _pf_data[PFE_GAMELOOP].GetRate();
466  bool have_script = false;
467  this->rate_gameloop.SetRate(gl_rate, _pf_data[PFE_GAMELOOP].expected_rate);
468  this->speed_gameloop.SetRate(gl_rate / _pf_data[PFE_GAMELOOP].expected_rate, 1.0);
469  if (this->small) return; // in small mode, this is everything needed
470 
471  this->rate_drawing.SetRate(_pf_data[PFE_DRAWING].GetRate(), _settings_client.gui.refresh_rate);
472 
473  int new_active = 0;
474  for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) {
475  this->times_shortterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(8), MILLISECONDS_PER_TICK);
476  this->times_longterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(NUM_FRAMERATE_POINTS), MILLISECONDS_PER_TICK);
477  if (_pf_data[e].num_valid > 0) {
478  new_active++;
479  if (e == PFE_GAMESCRIPT || e >= PFE_AI0) have_script = true;
480  }
481  }
482 
483  if (this->showing_memory != have_script) {
484  NWidgetStacked *plane = this->GetWidget<NWidgetStacked>(WID_FRW_SEL_MEMORY);
485  plane->SetDisplayedPlane(have_script ? 0 : SZSP_VERTICAL);
486  this->showing_memory = have_script;
487  }
488 
489  if (new_active != this->num_active) {
490  this->num_active = new_active;
491  Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
492  sb->SetCount(this->num_active);
493  sb->SetCapacity(std::min(this->num_displayed, this->num_active));
494  this->ReInit();
495  }
496  }
497 
498  void SetStringParameters(int widget) const override
499  {
500  switch (widget) {
501  case WID_FRW_CAPTION:
502  /* When the window is shaded, the caption shows game loop rate and speed factor */
503  if (!this->small) break;
504  SetDParam(0, this->rate_gameloop.strid);
505  this->rate_gameloop.InsertDParams(1);
506  this->speed_gameloop.InsertDParams(3);
507  break;
508 
509  case WID_FRW_RATE_GAMELOOP:
510  SetDParam(0, this->rate_gameloop.strid);
511  this->rate_gameloop.InsertDParams(1);
512  break;
513  case WID_FRW_RATE_DRAWING:
514  SetDParam(0, this->rate_drawing.strid);
515  this->rate_drawing.InsertDParams(1);
516  break;
517  case WID_FRW_RATE_FACTOR:
518  this->speed_gameloop.InsertDParams(0);
519  break;
520  case WID_FRW_INFO_DATA_POINTS:
522  break;
523  }
524  }
525 
526  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
527  {
528  switch (widget) {
529  case WID_FRW_RATE_GAMELOOP:
530  SetDParam(0, STR_FRAMERATE_FPS_GOOD);
531  SetDParam(1, 999999);
532  SetDParam(2, 2);
533  *size = GetStringBoundingBox(STR_FRAMERATE_RATE_GAMELOOP);
534  break;
535  case WID_FRW_RATE_DRAWING:
536  SetDParam(0, STR_FRAMERATE_FPS_GOOD);
537  SetDParam(1, 999999);
538  SetDParam(2, 2);
539  *size = GetStringBoundingBox(STR_FRAMERATE_RATE_BLITTER);
540  break;
541  case WID_FRW_RATE_FACTOR:
542  SetDParam(0, 999999);
543  SetDParam(1, 2);
544  *size = GetStringBoundingBox(STR_FRAMERATE_SPEED_FACTOR);
545  break;
546 
547  case WID_FRW_TIMES_NAMES: {
548  size->width = 0;
550  resize->width = 0;
551  resize->height = FONT_HEIGHT_NORMAL;
552  for (PerformanceElement e : DISPLAY_ORDER_PFE) {
553  if (_pf_data[e].num_valid == 0) continue;
554  Dimension line_size;
555  if (e < PFE_AI0) {
556  line_size = GetStringBoundingBox(STR_FRAMERATE_GAMELOOP + e);
557  } else {
558  SetDParam(0, e - PFE_AI0 + 1);
559  SetDParamStr(1, GetAIName(e - PFE_AI0));
560  line_size = GetStringBoundingBox(STR_FRAMERATE_AI);
561  }
562  size->width = std::max(size->width, line_size.width);
563  }
564  break;
565  }
566 
567  case WID_FRW_TIMES_CURRENT:
568  case WID_FRW_TIMES_AVERAGE:
569  case WID_FRW_ALLOCSIZE: {
570  *size = GetStringBoundingBox(STR_FRAMERATE_CURRENT + (widget - WID_FRW_TIMES_CURRENT));
571  SetDParam(0, 999999);
572  SetDParam(1, 2);
573  Dimension item_size = GetStringBoundingBox(STR_FRAMERATE_MS_GOOD);
574  size->width = std::max(size->width, item_size.width);
575  size->height += FONT_HEIGHT_NORMAL * MIN_ELEMENTS + VSPACING;
576  resize->width = 0;
577  resize->height = FONT_HEIGHT_NORMAL;
578  break;
579  }
580  }
581  }
582 
584  void DrawElementTimesColumn(const Rect &r, StringID heading_str, const CachedDecimal *values) const
585  {
586  const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
587  uint16 skip = sb->GetPosition();
588  int drawable = this->num_displayed;
589  int y = r.top;
590  DrawString(r.left, r.right, y, heading_str, TC_FROMSTRING, SA_CENTER, true);
592  for (PerformanceElement e : DISPLAY_ORDER_PFE) {
593  if (_pf_data[e].num_valid == 0) continue;
594  if (skip > 0) {
595  skip--;
596  } else {
597  values[e].InsertDParams(0);
598  DrawString(r.left, r.right, y, values[e].strid, TC_FROMSTRING, SA_RIGHT);
599  y += FONT_HEIGHT_NORMAL;
600  drawable--;
601  if (drawable == 0) break;
602  }
603  }
604  }
605 
606  void DrawElementAllocationsColumn(const Rect &r) const
607  {
608  const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
609  uint16 skip = sb->GetPosition();
610  int drawable = this->num_displayed;
611  int y = r.top;
612  DrawString(r.left, r.right, y, STR_FRAMERATE_MEMORYUSE, TC_FROMSTRING, SA_CENTER, true);
614  for (PerformanceElement e : DISPLAY_ORDER_PFE) {
615  if (_pf_data[e].num_valid == 0) continue;
616  if (skip > 0) {
617  skip--;
618  } else if (e == PFE_GAMESCRIPT || e >= PFE_AI0) {
619  if (e == PFE_GAMESCRIPT) {
620  SetDParam(0, Game::GetInstance()->GetAllocatedMemory());
621  } else {
622  SetDParam(0, Company::Get(e - PFE_AI0)->ai_instance->GetAllocatedMemory());
623  }
624  DrawString(r.left, r.right, y, STR_FRAMERATE_BYTES_GOOD, TC_FROMSTRING, SA_RIGHT);
625  y += FONT_HEIGHT_NORMAL;
626  drawable--;
627  if (drawable == 0) break;
628  } else {
629  /* skip non-script */
630  y += FONT_HEIGHT_NORMAL;
631  drawable--;
632  if (drawable == 0) break;
633  }
634  }
635  }
636 
637  void DrawWidget(const Rect &r, int widget) const override
638  {
639  switch (widget) {
640  case WID_FRW_TIMES_NAMES: {
641  /* Render a column of titles for performance element names */
642  const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
643  uint16 skip = sb->GetPosition();
644  int drawable = this->num_displayed;
645  int y = r.top + FONT_HEIGHT_NORMAL + VSPACING; // first line contains headings in the value columns
646  for (PerformanceElement e : DISPLAY_ORDER_PFE) {
647  if (_pf_data[e].num_valid == 0) continue;
648  if (skip > 0) {
649  skip--;
650  } else {
651  if (e < PFE_AI0) {
652  DrawString(r.left, r.right, y, STR_FRAMERATE_GAMELOOP + e, TC_FROMSTRING, SA_LEFT);
653  } else {
654  SetDParam(0, e - PFE_AI0 + 1);
655  SetDParamStr(1, GetAIName(e - PFE_AI0));
656  DrawString(r.left, r.right, y, STR_FRAMERATE_AI, TC_FROMSTRING, SA_LEFT);
657  }
658  y += FONT_HEIGHT_NORMAL;
659  drawable--;
660  if (drawable == 0) break;
661  }
662  }
663  break;
664  }
665  case WID_FRW_TIMES_CURRENT:
666  /* Render short-term average values */
667  DrawElementTimesColumn(r, STR_FRAMERATE_CURRENT, this->times_shortterm);
668  break;
669  case WID_FRW_TIMES_AVERAGE:
670  /* Render averages of all recorded values */
671  DrawElementTimesColumn(r, STR_FRAMERATE_AVERAGE, this->times_longterm);
672  break;
673  case WID_FRW_ALLOCSIZE:
674  DrawElementAllocationsColumn(r);
675  break;
676  }
677  }
678 
679  void OnClick(Point pt, int widget, int click_count) override
680  {
681  switch (widget) {
682  case WID_FRW_TIMES_NAMES:
683  case WID_FRW_TIMES_CURRENT:
684  case WID_FRW_TIMES_AVERAGE: {
685  /* Open time graph windows when clicking detail measurement lines */
686  const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
687  int line = sb->GetScrolledRowFromWidget(pt.y - FONT_HEIGHT_NORMAL - VSPACING, this, widget, VSPACING, FONT_HEIGHT_NORMAL);
688  if (line != INT_MAX) {
689  line++;
690  /* Find the visible line that was clicked */
691  for (PerformanceElement e : DISPLAY_ORDER_PFE) {
692  if (_pf_data[e].num_valid > 0) line--;
693  if (line == 0) {
695  break;
696  }
697  }
698  }
699  break;
700  }
701  }
702  }
703 
704  void OnResize() override
705  {
706  auto *wid = this->GetWidget<NWidgetResizeBase>(WID_FRW_TIMES_NAMES);
707  this->num_displayed = (wid->current_y - wid->min_y - VSPACING) / FONT_HEIGHT_NORMAL - 1; // subtract 1 for headings
708  this->GetScrollbar(WID_FRW_SCROLLBAR)->SetCapacity(this->num_displayed);
709  }
710 };
711 
712 static WindowDesc _framerate_display_desc(
713  WDP_AUTO, "framerate_display", 0, 0,
715  0,
716  _framerate_window_widgets, lengthof(_framerate_window_widgets)
717 );
718 
719 
721 static const NWidgetPart _frametime_graph_window_widgets[] = {
723  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
724  NWidget(WWT_CAPTION, COLOUR_GREY, WID_FGW_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
725  NWidget(WWT_STICKYBOX, COLOUR_GREY),
726  EndContainer(),
727  NWidget(WWT_PANEL, COLOUR_GREY),
729  NWidget(WWT_EMPTY, COLOUR_GREY, WID_FGW_GRAPH),
730  EndContainer(),
731  EndContainer(),
732 };
733 
738 
741 
742  FrametimeGraphWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
743  {
744  this->element = (PerformanceElement)number;
745  this->horizontal_scale = 4;
746  this->vertical_scale = TIMESTAMP_PRECISION / 10;
747  this->next_scale_update.SetInterval(1);
748 
749  this->InitNested(number);
750  }
751 
752  void SetStringParameters(int widget) const override
753  {
754  switch (widget) {
755  case WID_FGW_CAPTION:
756  if (this->element < PFE_AI0) {
757  SetDParam(0, STR_FRAMETIME_CAPTION_GAMELOOP + this->element);
758  } else {
759  SetDParam(0, STR_FRAMETIME_CAPTION_AI);
760  SetDParam(1, this->element - PFE_AI0 + 1);
761  SetDParamStr(2, GetAIName(this->element - PFE_AI0));
762  }
763  break;
764  }
765  }
766 
767  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
768  {
769  if (widget == WID_FGW_GRAPH) {
770  SetDParam(0, 100);
771  Dimension size_ms_label = GetStringBoundingBox(STR_FRAMERATE_GRAPH_MILLISECONDS);
772  SetDParam(0, 100);
773  Dimension size_s_label = GetStringBoundingBox(STR_FRAMERATE_GRAPH_SECONDS);
774 
775  /* Size graph in height to fit at least 10 vertical labels with space between, or at least 100 pixels */
776  graph_size.height = std::max(100u, 10 * (size_ms_label.height + 1));
777  /* Always 2:1 graph area */
778  graph_size.width = 2 * graph_size.height;
779  *size = graph_size;
780 
781  size->width += size_ms_label.width + 2;
782  size->height += size_s_label.height + 2;
783  }
784  }
785 
786  void SelectHorizontalScale(TimingMeasurement range)
787  {
788  /* Determine horizontal scale based on period covered by 60 points
789  * (slightly less than 2 seconds at full game speed) */
790  struct ScaleDef { TimingMeasurement range; int scale; };
791  static const ScaleDef hscales[] = {
792  { 120, 60 },
793  { 10, 20 },
794  { 5, 10 },
795  { 3, 4 },
796  { 1, 2 },
797  };
798  for (const ScaleDef *sc = hscales; sc < hscales + lengthof(hscales); sc++) {
799  if (range < sc->range) this->horizontal_scale = sc->scale;
800  }
801  }
802 
803  void SelectVerticalScale(TimingMeasurement range)
804  {
805  /* Determine vertical scale based on peak value (within the horizontal scale + a bit) */
806  static const TimingMeasurement vscales[] = {
807  TIMESTAMP_PRECISION * 100,
808  TIMESTAMP_PRECISION * 10,
813  TIMESTAMP_PRECISION / 10,
814  TIMESTAMP_PRECISION / 50,
815  TIMESTAMP_PRECISION / 200,
816  };
817  for (const TimingMeasurement *sc = vscales; sc < vscales + lengthof(vscales); sc++) {
818  if (range < *sc) this->vertical_scale = (int)*sc;
819  }
820  }
821 
823  void UpdateScale()
824  {
825  const TimingMeasurement *durations = _pf_data[this->element].durations;
826  const TimingMeasurement *timestamps = _pf_data[this->element].timestamps;
827  int num_valid = _pf_data[this->element].num_valid;
828  int point = _pf_data[this->element].prev_index;
829 
830  TimingMeasurement lastts = timestamps[point];
831  TimingMeasurement time_sum = 0;
832  TimingMeasurement peak_value = 0;
833  int count = 0;
834 
835  /* Sensible default for when too few measurements are available */
836  this->horizontal_scale = 4;
837 
838  for (int i = 1; i < num_valid; i++) {
839  point--;
840  if (point < 0) point = NUM_FRAMERATE_POINTS - 1;
841 
842  TimingMeasurement value = durations[point];
843  if (value == PerformanceData::INVALID_DURATION) {
844  /* Skip gaps in data by pretending time is continuous across them */
845  lastts = timestamps[point];
846  continue;
847  }
848  if (value > peak_value) peak_value = value;
849  count++;
850 
851  /* Accumulate period of time covered by data */
852  time_sum += lastts - timestamps[point];
853  lastts = timestamps[point];
854 
855  /* Enough data to select a range and get decent data density */
856  if (count == 60) this->SelectHorizontalScale(time_sum / TIMESTAMP_PRECISION);
857 
858  /* End when enough points have been collected and the horizontal scale has been exceeded */
859  if (count >= 60 && time_sum >= (this->horizontal_scale + 2) * TIMESTAMP_PRECISION / 2) break;
860  }
861 
862  this->SelectVerticalScale(peak_value);
863  }
864 
865  void OnRealtimeTick(uint delta_ms) override
866  {
867  this->SetDirty();
868 
869  if (this->next_scale_update.Elapsed(delta_ms)) {
870  this->next_scale_update.SetInterval(500);
871  this->UpdateScale();
872  }
873  }
874 
876  template<typename T>
877  static inline T Scinterlate(T dst_min, T dst_max, T src_min, T src_max, T value)
878  {
879  T dst_diff = dst_max - dst_min;
880  T src_diff = src_max - src_min;
881  return (value - src_min) * dst_diff / src_diff + dst_min;
882  }
883 
884  void DrawWidget(const Rect &r, int widget) const override
885  {
886  if (widget == WID_FGW_GRAPH) {
887  const TimingMeasurement *durations = _pf_data[this->element].durations;
888  const TimingMeasurement *timestamps = _pf_data[this->element].timestamps;
889  int point = _pf_data[this->element].prev_index;
890 
891  const int x_zero = r.right - (int)this->graph_size.width;
892  const int x_max = r.right;
893  const int y_zero = r.top + (int)this->graph_size.height;
894  const int y_max = r.top;
895  const int c_grid = PC_DARK_GREY;
896  const int c_lines = PC_BLACK;
897  const int c_peak = PC_DARK_RED;
898 
899  const TimingMeasurement draw_horz_scale = (TimingMeasurement)this->horizontal_scale * TIMESTAMP_PRECISION / 2;
900  const TimingMeasurement draw_vert_scale = (TimingMeasurement)this->vertical_scale;
901 
902  /* Number of \c horizontal_scale units in each horizontal division */
903  const uint horz_div_scl = (this->horizontal_scale <= 20) ? 1 : 10;
904  /* Number of divisions of the horizontal axis */
905  const uint horz_divisions = this->horizontal_scale / horz_div_scl;
906  /* Number of divisions of the vertical axis */
907  const uint vert_divisions = 10;
908 
909  /* Draw division lines and labels for the vertical axis */
910  for (uint division = 0; division < vert_divisions; division++) {
911  int y = Scinterlate(y_zero, y_max, 0, (int)vert_divisions, (int)division);
912  GfxDrawLine(x_zero, y, x_max, y, c_grid);
913  if (division % 2 == 0) {
914  if ((TimingMeasurement)this->vertical_scale > TIMESTAMP_PRECISION) {
915  SetDParam(0, this->vertical_scale * division / 10 / TIMESTAMP_PRECISION);
916  DrawString(r.left, x_zero - 2, y - FONT_HEIGHT_SMALL, STR_FRAMERATE_GRAPH_SECONDS, TC_GREY, SA_RIGHT | SA_FORCE, false, FS_SMALL);
917  } else {
918  SetDParam(0, this->vertical_scale * division / 10 * 1000 / TIMESTAMP_PRECISION);
919  DrawString(r.left, x_zero - 2, y - FONT_HEIGHT_SMALL, STR_FRAMERATE_GRAPH_MILLISECONDS, TC_GREY, SA_RIGHT | SA_FORCE, false, FS_SMALL);
920  }
921  }
922  }
923  /* Draw division lines and labels for the horizontal axis */
924  for (uint division = horz_divisions; division > 0; division--) {
925  int x = Scinterlate(x_zero, x_max, 0, (int)horz_divisions, (int)horz_divisions - (int)division);
926  GfxDrawLine(x, y_max, x, y_zero, c_grid);
927  if (division % 2 == 0) {
928  SetDParam(0, division * horz_div_scl / 2);
929  DrawString(x, x_max, y_zero + 2, STR_FRAMERATE_GRAPH_SECONDS, TC_GREY, SA_LEFT | SA_FORCE, false, FS_SMALL);
930  }
931  }
932 
933  /* Position of last rendered data point */
934  Point lastpoint = {
935  x_max,
936  (int)Scinterlate<int64>(y_zero, y_max, 0, this->vertical_scale, durations[point])
937  };
938  /* Timestamp of last rendered data point */
939  TimingMeasurement lastts = timestamps[point];
940 
941  TimingMeasurement peak_value = 0;
942  Point peak_point = { 0, 0 };
943  TimingMeasurement value_sum = 0;
944  TimingMeasurement time_sum = 0;
945  int points_drawn = 0;
946 
947  for (int i = 1; i < NUM_FRAMERATE_POINTS; i++) {
948  point--;
949  if (point < 0) point = NUM_FRAMERATE_POINTS - 1;
950 
951  TimingMeasurement value = durations[point];
952  if (value == PerformanceData::INVALID_DURATION) {
953  /* Skip gaps in measurements, pretend the data points on each side are continuous */
954  lastts = timestamps[point];
955  continue;
956  }
957 
958  /* Use total time period covered for value along horizontal axis */
959  time_sum += lastts - timestamps[point];
960  lastts = timestamps[point];
961  /* Stop if past the width of the graph */
962  if (time_sum > draw_horz_scale) break;
963 
964  /* Draw line from previous point to new point */
965  Point newpoint = {
966  (int)Scinterlate<int64>(x_zero, x_max, 0, (int64)draw_horz_scale, (int64)draw_horz_scale - (int64)time_sum),
967  (int)Scinterlate<int64>(y_zero, y_max, 0, (int64)draw_vert_scale, (int64)value)
968  };
969  assert(newpoint.x <= lastpoint.x);
970  GfxDrawLine(lastpoint.x, lastpoint.y, newpoint.x, newpoint.y, c_lines);
971  lastpoint = newpoint;
972 
973  /* Record peak and average value across graphed data */
974  value_sum += value;
975  points_drawn++;
976  if (value > peak_value) {
977  peak_value = value;
978  peak_point = newpoint;
979  }
980  }
981 
982  /* If the peak value is significantly larger than the average, mark and label it */
983  if (points_drawn > 0 && peak_value > TIMESTAMP_PRECISION / 100 && 2 * peak_value > 3 * value_sum / points_drawn) {
984  TextColour tc_peak = (TextColour)(TC_IS_PALETTE_COLOUR | c_peak);
985  GfxFillRect(peak_point.x - 1, peak_point.y - 1, peak_point.x + 1, peak_point.y + 1, c_peak);
986  SetDParam(0, peak_value * 1000 / TIMESTAMP_PRECISION);
987  int label_y = std::max(y_max, peak_point.y - FONT_HEIGHT_SMALL);
988  if (peak_point.x - x_zero > (int)this->graph_size.width / 2) {
989  DrawString(x_zero, peak_point.x - 2, label_y, STR_FRAMERATE_GRAPH_MILLISECONDS, tc_peak, SA_RIGHT | SA_FORCE, false, FS_SMALL);
990  } else {
991  DrawString(peak_point.x + 2, x_max, label_y, STR_FRAMERATE_GRAPH_MILLISECONDS, tc_peak, SA_LEFT | SA_FORCE, false, FS_SMALL);
992  }
993  }
994  }
995  }
996 };
997 
998 static WindowDesc _frametime_graph_window_desc(
999  WDP_AUTO, "frametime_graph", 140, 90,
1001  0,
1002  _frametime_graph_window_widgets, lengthof(_frametime_graph_window_widgets)
1003 );
1004 
1005 
1006 
1009 {
1010  AllocateWindowDescFront<FramerateWindow>(&_framerate_display_desc, 0);
1011 }
1012 
1015 {
1016  if (elem < PFE_FIRST || elem >= PFE_MAX) return; // maybe warn?
1017  AllocateWindowDescFront<FrametimeGraphWindow>(&_frametime_graph_window_desc, elem, true);
1018 }
1019 
1022 {
1023  const int count1 = NUM_FRAMERATE_POINTS / 8;
1024  const int count2 = NUM_FRAMERATE_POINTS / 4;
1025  const int count3 = NUM_FRAMERATE_POINTS / 1;
1026 
1027  IConsolePrintF(TC_SILVER, "Based on num. data points: %d %d %d", count1, count2, count3);
1028 
1029  static const char *MEASUREMENT_NAMES[PFE_MAX] = {
1030  "Game loop",
1031  " GL station ticks",
1032  " GL train ticks",
1033  " GL road vehicle ticks",
1034  " GL ship ticks",
1035  " GL aircraft ticks",
1036  " GL landscape ticks",
1037  " GL link graph delays",
1038  "Drawing",
1039  " Viewport drawing",
1040  "Video output",
1041  "Sound mixing",
1042  "AI/GS scripts total",
1043  "Game script",
1044  };
1045  char ai_name_buf[128];
1046 
1047  static const PerformanceElement rate_elements[] = { PFE_GAMELOOP, PFE_DRAWING, PFE_VIDEO };
1048 
1049  bool printed_anything = false;
1050 
1051  for (const PerformanceElement *e = rate_elements; e < rate_elements + lengthof(rate_elements); e++) {
1052  auto &pf = _pf_data[*e];
1053  if (pf.num_valid == 0) continue;
1054  IConsolePrintF(TC_GREEN, "%s rate: %.2ffps (expected: %.2ffps)",
1055  MEASUREMENT_NAMES[*e],
1056  pf.GetRate(),
1057  pf.expected_rate);
1058  printed_anything = true;
1059  }
1060 
1061  for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) {
1062  auto &pf = _pf_data[e];
1063  if (pf.num_valid == 0) continue;
1064  const char *name;
1065  if (e < PFE_AI0) {
1066  name = MEASUREMENT_NAMES[e];
1067  } else {
1068  seprintf(ai_name_buf, lastof(ai_name_buf), "AI %d %s", e - PFE_AI0 + 1, GetAIName(e - PFE_AI0)),
1069  name = ai_name_buf;
1070  }
1071  IConsolePrintF(TC_LIGHT_BLUE, "%s times: %.2fms %.2fms %.2fms",
1072  name,
1073  pf.GetAverageDurationMilliseconds(count1),
1074  pf.GetAverageDurationMilliseconds(count2),
1075  pf.GetAverageDurationMilliseconds(count3));
1076  printed_anything = true;
1077  }
1078 
1079  if (!printed_anything) {
1080  IConsoleWarning("No performance measurements have been taken yet");
1081  }
1082 }
FrametimeGraphWindow::vertical_scale
int vertical_scale
number of TIMESTAMP_PRECISION units vertically
Definition: framerate_gui.cpp:735
game.hpp
anonymous_namespace{framerate_gui.cpp}::NUM_FRAMERATE_POINTS
const int NUM_FRAMERATE_POINTS
Number of data points to keep in buffer for each performance measurement.
Definition: framerate_gui.cpp:37
FrametimeGraphWindow::horizontal_scale
int horizontal_scale
number of half-second units horizontally
Definition: framerate_gui.cpp:736
anonymous_namespace{framerate_gui.cpp}::PerformanceData::GetRate
double GetRate()
Get current rate of a performance element, based on approximately the past one second of data.
Definition: framerate_gui.cpp:140
PFE_AI11
@ PFE_AI11
AI execution for player slot 12.
Definition: framerate_type.h:74
anonymous_namespace{framerate_gui.cpp}::PerformanceData::acc_duration
TimingMeasurement acc_duration
Current accumulated duration.
Definition: framerate_gui.cpp:59
anonymous_namespace{framerate_gui.cpp}::TIMESTAMP_PRECISION
const TimingMeasurement TIMESTAMP_PRECISION
Units a second is divided into in performance measurements
Definition: framerate_gui.cpp:39
GUISettings::refresh_rate
uint16 refresh_rate
How often we refresh the screen (time between draw-ticks).
Definition: settings_type.h:150
FramerateWindow
Definition: framerate_gui.cpp:387
game_instance.hpp
PFE_AI9
@ PFE_AI9
AI execution for player slot 10.
Definition: framerate_type.h:72
Pool::PoolItem<&_company_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:329
SetScrollbar
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1094
PFE_VIDEO
@ PFE_VIDEO
Speed of painting drawn video buffer.
Definition: framerate_type.h:59
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition: geometry_type.hpp:27
FramerateWindow::SetStringParameters
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Definition: framerate_gui.cpp:498
WWT_STICKYBOX
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:64
SetPadding
static NWidgetPart SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1045
Window::GetScrollbar
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:309
PFE_AI14
@ PFE_AI14
AI execution for player slot 15.
Definition: framerate_type.h:77
PC_DARK_RED
static const uint8 PC_DARK_RED
Dark red palette colour.
Definition: gfx_func.h:212
guitimer_func.h
FrametimeGraphWindow::OnRealtimeTick
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition: framerate_gui.cpp:865
Window::ReInit
void ReInit(int rx=0, int ry=0)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:995
company_base.h
anonymous_namespace{framerate_gui.cpp}::PerformanceData::BeginAccumulate
void BeginAccumulate(TimingMeasurement start_time)
Begin an accumulation of multiple measurements into a single value, from a given start time.
Definition: framerate_gui.cpp:83
FrametimeGraphWindow::Scinterlate
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.
Definition: framerate_gui.cpp:877
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:59
FrametimeGraphWindow::DrawWidget
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Definition: framerate_gui.cpp:884
Scrollbar::GetScrolledRowFromWidget
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1966
SA_RIGHT
@ SA_RIGHT
Right align the text (must be a single bit).
Definition: gfx_func.h:98
PFE_AI1
@ PFE_AI1
AI execution for player slot 2.
Definition: framerate_type.h:64
SA_LEFT
@ SA_LEFT
Left align the text.
Definition: gfx_func.h:96
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:73
PFE_GL_ROADVEHS
@ PFE_GL_ROADVEHS
Time spend processing road vehicles.
Definition: framerate_type.h:52
anonymous_namespace{framerate_gui.cpp}::PerformanceData::timestamps
TimingMeasurement timestamps[NUM_FRAMERATE_POINTS]
Start time of each cycle of the performance element, circular buffer.
Definition: framerate_gui.cpp:48
FramerateWindow::times_shortterm
CachedDecimal times_shortterm[PFE_MAX]
cached short term average times
Definition: framerate_gui.cpp:426
anonymous_namespace{framerate_gui.cpp}::GL_RATE
static const double GL_RATE
Game loop rate, cycles per second
Definition: framerate_gui.cpp:176
Scrollbar::SetCount
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:669
anonymous_namespace{framerate_gui.cpp}::PerformanceData::AddPause
void AddPause(TimingMeasurement start_time)
Indicate a pause/expected discontinuity in processing the element.
Definition: framerate_gui.cpp:103
ConPrintFramerate
void ConPrintFramerate()
Print performance statistics to game console.
Definition: framerate_gui.cpp:1021
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:250
FrametimeGraphWindow::UpdateWidgetSize
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
Definition: framerate_gui.cpp:767
FrametimeGraphWindow::next_scale_update
GUITimer next_scale_update
interval for next scale update
Definition: framerate_gui.cpp:737
PFE_GL_LINKGRAPH
@ PFE_GL_LINKGRAPH
Time spent waiting for link graph background jobs.
Definition: framerate_type.h:56
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:79
DrawString
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:640
WWT_EMPTY
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget array.
Definition: widget_type.h:46
WindowNumber
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:711
PerformanceAccumulator::~PerformanceAccumulator
~PerformanceAccumulator()
Finish and add one block of the accumulating value.
Definition: framerate_gui.cpp:294
SA_CENTER
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_func.h:106
SA_FORCE
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition: gfx_func.h:108
Scrollbar
Scrollbar data structure.
Definition: widget_type.h:588
ShowFrametimeGraphWindow
void ShowFrametimeGraphWindow(PerformanceElement elem)
Open a graph window for a performance element.
Definition: framerate_gui.cpp:1014
SetDParam
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
NWidgetPart
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:909
SetDataTip
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1013
PerformanceMeasurer::SetInactive
static void SetInactive(PerformanceElement elem)
Mark a performance element as not currently in use.
Definition: framerate_gui.cpp:264
PFE_GL_LANDSCAPE
@ PFE_GL_LANDSCAPE
Time spent processing other world features.
Definition: framerate_type.h:55
GetStringBoundingBox
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:842
PerformanceElement
PerformanceElement
Elements of game performance that can be measured.
Definition: framerate_type.h:47
anonymous_namespace{framerate_gui.cpp}::PerformanceData::num_valid
int num_valid
Number of data points recorded, clamped to NUM_FRAMERATE_POINTS.
Definition: framerate_gui.cpp:56
PFE_GL_TRAINS
@ PFE_GL_TRAINS
Time spent processing trains.
Definition: framerate_type.h:51
ai_info.hpp
console_type.h
gfx_func.h
WindowDesc
High level window description.
Definition: window_gui.h:166
PerformanceMeasurer::SetExpectedRate
void SetExpectedRate(double rate)
Set the rate of expected cycles per second of a performance element.
Definition: framerate_gui.cpp:258
window_gui.h
GUITimer
Definition: guitimer_func.h:13
WDP_AUTO
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:154
PFE_AI7
@ PFE_AI7
AI execution for player slot 8.
Definition: framerate_type.h:70
WC_FRAMETIME_GRAPH
@ WC_FRAMETIME_GRAPH
Frame time graph; Window numbers:
Definition: window_type.h:692
Window::resize
ResizeInfo resize
Resize information.
Definition: window_gui.h:322
Window::InitNested
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1861
Window::SetDirty
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:984
FramerateWindow::DrawElementTimesColumn
void DrawElementTimesColumn(const Rect &r, StringID heading_str, const CachedDecimal *values) const
Render a column of formatted average durations.
Definition: framerate_gui.cpp:584
FS_SMALL
@ FS_SMALL
Index of the small font in the font tables.
Definition: gfx_type.h:208
FrametimeGraphWindow
Definition: framerate_gui.cpp:734
PFE_GL_SHIPS
@ PFE_GL_SHIPS
Time spent processing ships.
Definition: framerate_type.h:53
PerformanceMeasurer::~PerformanceMeasurer
~PerformanceMeasurer()
Finish a cycle of a measured element and store the measurement taken.
Definition: framerate_gui.cpp:243
ShowFramerateWindow
void ShowFramerateWindow()
Open the general framerate window.
Definition: framerate_gui.cpp:1008
PFE_AI2
@ PFE_AI2
AI execution for player slot 3.
Definition: framerate_type.h:65
ai_instance.hpp
anonymous_namespace{framerate_gui.cpp}::PerformanceData::PerformanceData
PerformanceData(double expected_rate)
Initialize a data element with an expected collection rate.
Definition: framerate_gui.cpp:69
TC_IS_PALETTE_COLOUR
@ TC_IS_PALETTE_COLOUR
Colour value is already a real palette colour index, not an index of a StringColour.
Definition: gfx_type.h:273
safeguards.h
Company::IsValidAiID
static bool IsValidAiID(size_t index)
Is this company a valid company, controlled by the computer (a NoAI program)?
Definition: company_base.h:133
FrametimeGraphWindow::UpdateScale
void UpdateScale()
Recalculate the graph scaling factors based on current recorded data.
Definition: framerate_gui.cpp:823
PerformanceMeasurer::PerformanceMeasurer
PerformanceMeasurer(PerformanceElement elem)
Begin a cycle of a measured element.
Definition: framerate_gui.cpp:234
FramerateWindow::OnRealtimeTick
void OnRealtimeTick(uint delta_ms) override
Called periodically.
Definition: framerate_gui.cpp:445
PFE_DRAWING
@ PFE_DRAWING
Speed of drawing world and GUI.
Definition: framerate_type.h:57
sprites.h
Point
Coordinates of a point in 2D.
Definition: geometry_type.hpp:21
PFE_AI12
@ PFE_AI12
AI execution for player slot 13.
Definition: framerate_type.h:75
PFE_GL_AIRCRAFT
@ PFE_GL_AIRCRAFT
Time spent processing aircraft.
Definition: framerate_type.h:54
PFE_AI10
@ PFE_AI10
AI execution for player slot 11.
Definition: framerate_type.h:73
PFE_MAX
@ PFE_MAX
End of enum, must be last.
Definition: framerate_type.h:78
PC_BLACK
static const uint8 PC_BLACK
Black palette colour.
Definition: gfx_func.h:206
GfxFillRect
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition: gfx.cpp:114
anonymous_namespace{framerate_gui.cpp}::PerformanceData::expected_rate
double expected_rate
Expected number of cycles per second when the system is running without slowdowns.
Definition: framerate_gui.cpp:50
FramerateWindow::MIN_ELEMENTS
static constexpr int MIN_ELEMENTS
smallest number of elements to display
Definition: framerate_gui.cpp:430
anonymous_namespace{framerate_gui.cpp}::PerformanceData::prev_index
int prev_index
Last index written to in durations and timestamps.
Definition: framerate_gui.cpp:54
NWidgetStacked::SetDisplayedPlane
void SetDisplayedPlane(int plane)
Select which plane to show (for NWID_SELECTION only).
Definition: widget.cpp:1091
NWidgetStacked
Stacked widgets, widgets all occupying the same space in the window.
Definition: widget_type.h:404
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:38
PerformanceMeasurer::Paused
static void Paused(PerformanceElement elem)
Indicate that a cycle of "pause" where no processing occurs.
Definition: framerate_gui.cpp:275
NWID_VERTICAL
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:75
FONT_HEIGHT_SMALL
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:176
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:67
WWT_RESIZEBOX
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:66
string_func.h
Scrollbar::SetCapacity
void SetCapacity(int capacity)
Set the capacity of visible elements.
Definition: widget_type.h:685
PFE_GAMESCRIPT
@ PFE_GAMESCRIPT
Game script execution.
Definition: framerate_type.h:62
FramerateWindow::CachedDecimal
Definition: framerate_gui.cpp:394
FramerateWindow::DrawWidget
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Definition: framerate_gui.cpp:637
PerformanceAccumulator::PerformanceAccumulator
PerformanceAccumulator(PerformanceElement elem)
Begin measuring one block of the accumulating value.
Definition: framerate_gui.cpp:285
StringID
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
PFE_SOUND
@ PFE_SOUND
Speed of mixing audio samples.
Definition: framerate_type.h:60
FramerateWindow::times_longterm
CachedDecimal times_longterm[PFE_MAX]
cached long term average times
Definition: framerate_gui.cpp:427
EndContainer
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:998
anonymous_namespace{framerate_gui.cpp}::_pf_data
PerformanceData _pf_data[PFE_MAX]
Storage for all performance element measurements.
Definition: framerate_gui.cpp:183
strings_func.h
NWID_VSCROLLBAR
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:82
PFE_GAMELOOP
@ PFE_GAMELOOP
Speed of gameloop processing.
Definition: framerate_type.h:49
Window::IsShaded
bool IsShaded() const
Is window shaded currently?
Definition: window_gui.h:524
PFE_AI8
@ PFE_AI8
AI execution for player slot 9.
Definition: framerate_type.h:71
PFE_GL_ECONOMY
@ PFE_GL_ECONOMY
Time spent processing cargo movement.
Definition: framerate_type.h:50
WWT_TEXT
@ WWT_TEXT
Pure simple text.
Definition: widget_type.h:56
FrametimeGraphWindow::graph_size
Dimension graph_size
size of the main graph area (excluding axis labels)
Definition: framerate_gui.cpp:740
TimingMeasurement
uint64 TimingMeasurement
Type used to hold a performance timing measurement.
Definition: framerate_type.h:83
WC_FRAMERATE_DISPLAY
@ WC_FRAMERATE_DISPLAY
Framerate display; Window numbers:
Definition: window_type.h:686
anonymous_namespace{framerate_gui.cpp}::PerformanceData::AddAccumulate
void AddAccumulate(TimingMeasurement duration)
Accumulate a period onto the current measurement.
Definition: framerate_gui.cpp:97
FONT_HEIGHT_NORMAL
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:179
NWidget
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1113
framerate_type.h
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:48
PFE_AI3
@ PFE_AI3
AI execution for player slot 4.
Definition: framerate_type.h:66
PFE_AI6
@ PFE_AI6
AI execution for player slot 7.
Definition: framerate_type.h:69
Scrollbar::GetPosition
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:630
PFE_ALLSCRIPTS
@ PFE_ALLSCRIPTS
Sum of all GS/AI scripts.
Definition: framerate_type.h:61
anonymous_namespace{framerate_gui.cpp}::PerformanceData
Definition: framerate_gui.cpp:41
seprintf
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:442
FramerateWindow::rate_drawing
CachedDecimal rate_drawing
cached drawing frame rate
Definition: framerate_gui.cpp:424
GUITimer::Elapsed
bool Elapsed(uint delta)
Test if a timer has elapsed.
Definition: guitimer_func.h:55
framerate_widget.h
anonymous_namespace{framerate_gui.cpp}::PerformanceData::Add
void Add(TimingMeasurement start_time, TimingMeasurement end_time)
Collect a complete measurement, given start and ending times for a processing block.
Definition: framerate_gui.cpp:72
MILLISECONDS_PER_TICK
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition: gfx_type.h:310
window_func.h
FramerateWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition: framerate_gui.cpp:704
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:367
SetPIP
static NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1075
FrametimeGraphWindow::SetStringParameters
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Definition: framerate_gui.cpp:752
FramerateWindow::VSPACING
static constexpr int VSPACING
space between column heading and values
Definition: framerate_gui.cpp:429
PFE_AI5
@ PFE_AI5
AI execution for player slot 6.
Definition: framerate_type.h:68
PerformanceAccumulator::Reset
static void Reset(PerformanceElement elem)
Store the previous accumulator value and reset for a new cycle of accumulating measurements.
Definition: framerate_gui.cpp:304
PFE_AI13
@ PFE_AI13
AI execution for player slot 14.
Definition: framerate_type.h:76
anonymous_namespace{framerate_gui.cpp}::PerformanceData::next_index
int next_index
Next index to write to in durations and timestamps.
Definition: framerate_gui.cpp:52
anonymous_namespace{framerate_gui.cpp}::PerformanceData::durations
TimingMeasurement durations[NUM_FRAMERATE_POINTS]
Time spent processing each cycle of the performance element, circular buffer.
Definition: framerate_gui.cpp:46
FrametimeGraphWindow::element
PerformanceElement element
what element this window renders graph for
Definition: framerate_gui.cpp:739
Window
Data structure for an opened window.
Definition: window_gui.h:276
SZSP_VERTICAL
@ SZSP_VERTICAL
Display plane with zero size horizontally, and filling and resizing vertically.
Definition: widget_type.h:387
FramerateWindow::rate_gameloop
CachedDecimal rate_gameloop
cached game loop tick rate
Definition: framerate_gui.cpp:423
PFE_AI4
@ PFE_AI4
AI execution for player slot 5.
Definition: framerate_type.h:67
FramerateWindow::OnClick
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition: framerate_gui.cpp:679
PFE_AI0
@ PFE_AI0
AI execution for player slot 1.
Definition: framerate_type.h:63
PC_DARK_GREY
static const uint8 PC_DARK_GREY
Dark grey palette colour.
Definition: gfx_func.h:207
console_func.h
anonymous_namespace{framerate_gui.cpp}::PerformanceData::GetAverageDurationMilliseconds
double GetAverageDurationMilliseconds(int count)
Get average cycle processing time over a number of data points.
Definition: framerate_gui.cpp:116
NWID_SELECTION
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:78
IConsoleWarning
void IConsoleWarning(const char *string)
It is possible to print warnings to the console.
Definition: console.cpp:158
GetPerformanceTimer
static TimingMeasurement GetPerformanceTimer()
Return a timestamp with TIMESTAMP_PRECISION ticks per second precision.
Definition: framerate_gui.cpp:223
Game::GetInstance
static class GameInstance * GetInstance()
Get the current active instance.
Definition: game.hpp:111
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition: geometry_type.hpp:47
anonymous_namespace{framerate_gui.cpp}::PerformanceData::acc_timestamp
TimingMeasurement acc_timestamp
Start time for current accumulation cycle.
Definition: framerate_gui.cpp:61
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:383
FramerateWindow::UpdateWidgetSize
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
Definition: framerate_gui.cpp:526
IConsolePrintF
void CDECL IConsolePrintF(TextColour colour_code, const char *format,...)
Handle the printing of text entered into the console or redirected there by any other means.
Definition: console.cpp:125
SetDParamStr
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:286
PFE_DRAWWORLD
@ PFE_DRAWWORLD
Time spent drawing world viewports in GUI.
Definition: framerate_type.h:58
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition: settings_type.h:567
FramerateWindow::speed_gameloop
CachedDecimal speed_gameloop
cached game loop speed factor
Definition: framerate_gui.cpp:425
ResizeWindow
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
Resize the window.
Definition: window.cpp:2153
WWT_SHADEBOX
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:62