Blender V5.0
scene_fps.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <algorithm>
12#include <cmath>
13
14#include "BLI_math_base.h"
15
16#include "DNA_scene_types.h"
17
18#include "ED_scene.hh"
19
20#include "MEM_guardedalloc.h"
21
22using FrameSampleT = uint32_t;
24
30#define FIXED_UNIT FrameSampleT(65535)
31
33// #define USE_DEBUG_REPORT_ERROR_MARGIN
34
37#ifdef USE_DEBUG_REPORT_ERROR_MARGIN
38 double value_db;
39#endif
40};
41
46 double time_curr;
47 double time_prev;
48
49#ifdef USE_DEBUG_REPORT_ERROR_MARGIN
50 double error_sum;
51 int error_samples;
52#endif
53
56
61
65
67
70};
71
73{
74 if (scene->fps_info == nullptr) {
75 return;
76 }
77
78#ifndef NDEBUG
79 /* Assert this value has not somehow become out of sync as this would mean
80 * the reported frame-rate would be wrong. */
81 ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
82 FrameSumT times_fps_sum_cmp = 0;
83 for (int i = 0; i < fpsi->times_fps_num_set; i++) {
84 times_fps_sum_cmp += fpsi->times_fps[i].value;
85 }
86 BLI_assert(fpsi->times_fps_sum == times_fps_sum_cmp);
87#endif /* !NDEBUG */
88
89 MEM_freeN(static_cast<ScreenFrameRateInfo *>(scene->fps_info));
90 scene->fps_info = nullptr;
91}
92
93void ED_scene_fps_average_accumulate(Scene *scene, const short fps_samples, const double ltime)
94{
95 const float fps_target = float(scene->frames_per_second());
96 const int times_fps_num = (fps_samples > 0) ? fps_samples : max_ii(1, int(ceilf(fps_target)));
97
98 ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
99 if (fpsi) {
100 /* Reset when the target FPS changes.
101 * Needed redraw times from when a different FPS was set do not contribute
102 * to an average that is over/under the new target. */
103 if ((fpsi->fps_target != fps_target) || (fpsi->times_fps_num != times_fps_num)) {
104 MEM_freeN(fpsi);
105 fpsi = nullptr;
106 scene->fps_info = nullptr;
107 }
108 }
109
110 /* If there isn't any info, initialize it first. */
111 if (fpsi == nullptr) {
112 scene->fps_info = MEM_callocN(
113 sizeof(ScreenFrameRateInfo) + (sizeof(FrameSample) * times_fps_num), __func__);
114 fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
115 fpsi->fps_target = fps_target;
116 fpsi->times_fps_num = times_fps_num;
117 fpsi->times_fps_num_set = 0;
118
119 /* Use 100 for 2 decimal places (currently used for FPS display), could be configurable. */
120 const double decimal_places = 100.0;
121 fpsi->fps_target_is_fractional = std::round(fps_target) !=
122 (std::round(fps_target * decimal_places) / decimal_places);
123 }
124
125 /* Update the values. */
126 fpsi->time_curr = fpsi->time_prev;
127 fpsi->time_prev = ltime;
128
129 /* Mark as outdated. */
130 fpsi->fps_average = -1.0f;
131}
132
134{
135 ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
136 if (fpsi == nullptr) {
137 return false;
138 }
139
140 if (fpsi->time_prev == 0.0 || fpsi->time_curr == 0.0) {
141 /* The user should never see this. */
142 fpsi->fps_average = -1.0f;
143 return false;
144 }
145
146 if (fpsi->fps_average == -1.0) {
147 /* Doing an average for a more robust calculation. */
148 if (fpsi->times_fps_index >= fpsi->times_fps_num) {
149 fpsi->times_fps_index = 0;
150 }
151
152 const double fps_sample = 1.0 / (fpsi->time_prev - fpsi->time_curr);
153
154 {
155 const FrameSampleT fps_prev = (fpsi->times_fps_num_set == fpsi->times_fps_num) ?
156 fpsi->times_fps[fpsi->times_fps_index].value :
157 FrameSampleT(0);
158 const double fps_curr_db = std::round(fps_sample * double(FIXED_UNIT));
159 BLI_assert(fps_curr_db >= 0.0f);
160 const FrameSampleT fps_curr = FrameSampleT(fps_curr_db);
161 fpsi->times_fps[fpsi->times_fps_index].value = fps_curr;
162 fpsi->times_fps_sum -= fps_prev;
163 fpsi->times_fps_sum += fps_curr;
164 }
165#ifdef USE_DEBUG_REPORT_ERROR_MARGIN
166 fpsi->times_fps[fpsi->times_fps_index].value_db = fps_sample;
167#endif
168
169 fpsi->times_fps_index++;
170 fpsi->times_fps_num_set = std::max(fpsi->times_fps_index, fpsi->times_fps_num_set);
171 BLI_assert(fpsi->times_fps_num_set > 0);
172
173 fpsi->fps_average = float((double(fpsi->times_fps_sum) / double(fpsi->times_fps_num_set)) /
174 FIXED_UNIT);
175
176#ifdef USE_DEBUG_REPORT_ERROR_MARGIN
177 {
178 double fps_average_ref = 0.0f;
179 for (int i = 0; i < fpsi->times_fps_num_set; i++) {
180 fps_average_ref += fpsi->times_fps[i].value_db;
181 }
182 fps_average_ref = float(fps_average_ref / double(fpsi->times_fps_num_set));
183
184 const float error = float(fps_average_ref) - fpsi->fps_average;
185 fpsi->error_sum += error;
186 fpsi->error_samples += 1;
187 if ((fpsi->error_samples % 100) == 0) {
188 printf("%s error: %.16f over %d samples (average %.16f)\n",
189 __func__,
190 fpsi->error_sum,
191 fpsi->error_samples,
192 fpsi->error_sum / double(fpsi->error_samples));
193 }
194 }
195#endif /* USE_DEBUG_REPORT_ERROR_MARGIN */
196 }
197
198 r_state->fps_average = fpsi->fps_average;
199 r_state->fps_target = fpsi->fps_target;
201 return true;
202}
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int max_ii(int a, int b)
Read Guarded memory(de)allocation.
unsigned long long int uint64_t
nullptr float
#define printf(...)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void error(const char *str)
#define ceilf
void ED_scene_fps_average_clear(Scene *scene)
Definition scene_fps.cc:72
uint32_t FrameSampleT
Definition scene_fps.cc:22
#define FIXED_UNIT
Definition scene_fps.cc:30
bool ED_scene_fps_average_calc(const Scene *scene, SceneFPS_State *r_state)
Definition scene_fps.cc:133
void ED_scene_fps_average_accumulate(Scene *scene, const short fps_samples, const double ltime)
Definition scene_fps.cc:93
uint64_t FrameSumT
Definition scene_fps.cc:23
FrameSampleT value
Definition scene_fps.cc:36
bool fps_target_is_fractional
Definition ED_scene.hh:47
float fps_average
Definition ED_scene.hh:45
float fps_target
Definition ED_scene.hh:46
void * fps_info
bool fps_target_is_fractional
Definition scene_fps.cc:55
FrameSumT times_fps_sum
Definition scene_fps.cc:66
FrameSample times_fps[0]
Definition scene_fps.cc:69
i
Definition text_draw.cc:230