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:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user