Fix frame-rate display with multiple viewports open

Calculating the average FPS was done in the draw function which
also overwrote the old value. With multiple viewports the same
time-delta would be written multiple times causing the FPS display
not to use use REDRAW_FRAME_AVERAGE as intended.

Resolve by only calculating the average once per frame change across
multiple viewports.
This commit is contained in:
Campbell Barton
2023-08-25 15:45:56 +10:00
parent 09f61f6881
commit 1954baaed3
6 changed files with 89 additions and 49 deletions

View File

@@ -444,8 +444,15 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph);
/**
* Update frame rate info for viewport drawing.
* \param ltime: Time since the last update,
* compatible with the result of #PIL_check_seconds_timer.
*/
void ED_refresh_viewport_fps(bContext *C);
void ED_scene_fps_average_accumulate(struct Scene *scene, const double ltime);
/**
* Calculate an average (if it's not already calculated).
* \return True when #ScreenFrameRateInfo::fps_average should be used.
*/
bool ED_scene_fps_average_calc(const struct Scene *scene);
/**
* Toggle operator.
*/

View File

@@ -53,6 +53,10 @@ struct ScreenFrameRateInfo {
double lredrawtime;
float redrawtimes_fps[REDRAW_FRAME_AVERAGE];
short redrawtime_index;
/** The target FPS, use to reset on change. */
float fps_target;
/** Final result, ignore when -1.0. */
float fps_average;
};
/* ----------------------------------------------------- */

View File

@@ -1242,7 +1242,7 @@ float ED_view3d_grid_view_scale(Scene *scene,
const char **r_grid_unit);
/**
* \note The info that this uses is updated in #ED_refresh_viewport_fps,
* \note The info that this uses is updated in #ED_scene_fps_average_accumulate,
* which currently gets called during #SCREEN_OT_animation_step.
*/
void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset);

View File

@@ -1679,30 +1679,77 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
return area;
}
void ED_refresh_viewport_fps(bContext *C)
void ED_scene_fps_average_accumulate(Scene *scene, const double ltime)
{
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
Scene *scene = CTX_data_scene(C);
/* is anim playback running? */
if (animtimer && (U.uiflag & USER_SHOW_FPS)) {
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
/* if there isn't any info, init it first */
if (fpsi == nullptr) {
fpsi = static_cast<ScreenFrameRateInfo *>(
scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo),
"refresh_viewport_fps fps_info"));
}
/* update the values */
fpsi->redrawtime = fpsi->lredrawtime;
fpsi->lredrawtime = animtimer->ltime;
}
else {
/* playback stopped or shouldn't be running */
if ((U.uiflag & USER_SHOW_FPS) == 0) {
/* Playback stopped or shouldn't be running. */
MEM_SAFE_FREE(scene->fps_info);
return;
}
/* Playback running. */
const float fps_target = float(FPS);
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
/* Reset when the target FPS changes.
* Needed redraw times from when a different FPS was set do not contribute
* to an average that is over/under the new target. */
if (fpsi && (fpsi->fps_target != fps_target)) {
MEM_freeN(fpsi);
fpsi = nullptr;
scene->fps_info = nullptr;
}
/* If there isn't any info, initialize it first. */
if (fpsi == nullptr) {
fpsi = static_cast<ScreenFrameRateInfo *>(
scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo), __func__));
fpsi->fps_target = fps_target;
}
/* Update the values. */
fpsi->redrawtime = fpsi->lredrawtime;
fpsi->lredrawtime = ltime;
/* Mark as outdated. */
fpsi->fps_average = -1.0f;
}
bool ED_scene_fps_average_calc(const Scene *scene)
{
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
if (fpsi == nullptr) {
return false;
}
/* Doing an average for a more robust calculation. */
if (fpsi->lredrawtime == 0.0 && fpsi->redrawtime == 0.0) {
/* The user should never see this. */
fpsi->fps_average = -1.0f;
return false;
}
if (fpsi->fps_average != -1.0) {
return true;
}
fpsi->redrawtimes_fps[fpsi->redrawtime_index] = float(1.0 /
(fpsi->lredrawtime - fpsi->redrawtime));
float fps = 0.0f;
int tot = 0;
for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
if (fpsi->redrawtimes_fps[i]) {
fps += fpsi->redrawtimes_fps[i];
tot++;
}
}
if (tot) {
fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
fps = fps / tot;
}
fpsi->fps_average = fps;
return true;
}
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)

View File

@@ -4872,7 +4872,7 @@ static int screen_animation_step_invoke(bContext *C, wmOperator * /*op*/, const
* NOTE: this may not be accurate enough, since we might need this after modifiers/etc.
* have been calculated instead of just before updates have been done?
*/
ED_refresh_viewport_fps(C);
ED_scene_fps_average_accumulate(scene, wt->ltime);
/* Recalculate the time-step for the timer now that we've finished calculating this,
* since the frames-per-second value may have been changed.

View File

@@ -2576,43 +2576,25 @@ void ED_view3d_mats_rv3d_restore(RegionView3D *rv3d, RV3DMatrixStore *rv3dmat_pt
void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
{
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
/* 8 4-bytes chars (complex writing systems like Devanagari in UTF8 encoding) */
char printable[32];
if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) {
if (!ED_scene_fps_average_calc(scene)) {
return;
}
const ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
/* 8 4-bytes chars (complex writing systems like Devanagari in UTF8 encoding) */
char printable[32];
printable[0] = '\0';
/* Doing an average for a more robust calculation. */
fpsi->redrawtimes_fps[fpsi->redrawtime_index] = float(1.0 /
(fpsi->lredrawtime - fpsi->redrawtime));
float fps = 0.0f;
int tot = 0;
for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
if (fpsi->redrawtimes_fps[i]) {
fps += fpsi->redrawtimes_fps[i];
tot++;
}
}
if (tot) {
fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
fps = fps / tot;
}
const int font_id = BLF_default();
/* Is this more than half a frame behind? */
if (fps + 0.5f < float(FPS)) {
if (fpsi->fps_average + 0.5f < fpsi->fps_target) {
UI_FontThemeColor(font_id, TH_REDALERT);
SNPRINTF(printable, IFACE_("fps: %.2f"), fps);
SNPRINTF(printable, IFACE_("fps: %.2f"), fpsi->fps_average);
}
else {
UI_FontThemeColor(font_id, TH_TEXT_HI);
SNPRINTF(printable, IFACE_("fps: %i"), int(fps + 0.5f));
SNPRINTF(printable, IFACE_("fps: %i"), int(fpsi->fps_average + 0.5f));
}
BLF_enable(font_id, BLF_SHADOW);