UI: add a preference for the number of samples used for FPS playback

This was hard coded to 8, which can still result in a number that
jitters making the overall FPS difficult to measure.

The default is still 8, but this is now a preference that can be
increased for values that don't jitter as much.
This commit is contained in:
Campbell Barton
2023-08-25 19:22:05 +10:00
parent faff3d1d15
commit b150b47720
8 changed files with 63 additions and 29 deletions

View File

@@ -108,6 +108,7 @@ const UserDef U_default = {
.gp_euclideandist = 2,
.gp_eraser = 25,
.gp_settings = 0,
.playback_fps_samples = 8,
#ifdef __APPLE__
.gpu_backend = GPU_BACKEND_METAL,
#else

View File

@@ -720,6 +720,9 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
col.prop(view, "show_object_info", text="Object Info")
col.prop(view, "show_view_name", text="View Name")
col.prop(view, "show_playback_fps", text="Playback Frame Rate (FPS)")
row = col.row()
row.active = view.show_playback_fps
row.prop(view, "playback_fps_samples", text="Frame Rate Samples")
layout.separator()

View File

@@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 17
#define BLENDER_FILE_SUBVERSION 18
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -852,6 +852,10 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->node_preview_res = 120;
}
if (!USER_VERSION_ATLEAST(400, 18)) {
userdef->playback_fps_samples = 8;
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@@ -43,20 +43,24 @@ enum {
/* ----------------------------------------------------- */
#define REDRAW_FRAME_AVERAGE 8
/**
* For playback frame-rate info stored during runtime as `scene->fps_info`.
*/
struct ScreenFrameRateInfo {
double redrawtime;
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;
int redrawtimes_index;
int redrawtimes_num;
int redrawtimes_num_set;
/** Over allocate. */
float redrawtimes_fps[0];
};
/* ----------------------------------------------------- */

View File

@@ -1694,22 +1694,30 @@ void ED_scene_fps_average_accumulate(Scene *scene, const double ltime)
/* 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;
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
const int redrawtimes_num = U.playback_fps_samples ? U.playback_fps_samples :
max_ii(1, int(ceilf(fps_target)));
if (fpsi) {
/* 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->fps_target != fps_target) || (fpsi->redrawtimes_num != redrawtimes_num)) {
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__));
scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo) + (sizeof(float) * redrawtimes_num),
__func__);
fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
fpsi->fps_target = fps_target;
fpsi->redrawtimes_num = redrawtimes_num;
fpsi->redrawtimes_num_set = 0;
}
/* Update the values. */
@@ -1738,22 +1746,23 @@ bool ED_scene_fps_average_calc(const Scene *scene)
return true;
}
fpsi->redrawtimes_fps[fpsi->redrawtime_index] = float(1.0 /
(fpsi->lredrawtime - fpsi->redrawtime));
if (fpsi->redrawtimes_index >= fpsi->redrawtimes_num) {
fpsi->redrawtimes_index = 0;
}
/* Doing an average for a more robust calculation. */
fpsi->redrawtimes_fps[fpsi->redrawtimes_index] = float(1.0 /
(fpsi->lredrawtime - fpsi->redrawtime));
fpsi->redrawtimes_index++;
if (fpsi->redrawtimes_index > fpsi->redrawtimes_num_set) {
fpsi->redrawtimes_num_set = fpsi->redrawtimes_index;
}
BLI_assert(fpsi->redrawtimes_num_set > 0);
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++;
}
for (int i = 0; i < fpsi->redrawtimes_num_set; i++) {
fps += fpsi->redrawtimes_fps[i];
}
if (tot) {
fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
fps = fps / tot;
}
fpsi->fps_average = fps;
fpsi->fps_average = fps / float(fpsi->redrawtimes_num_set);
return true;
}

View File

@@ -923,7 +923,10 @@ typedef struct UserDef {
/** #eGPUBackendType */
short gpu_backend;
char _pad7[4];
/** Number of samples for FPS display calculations. */
uchar playback_fps_samples;
char _pad7[3];
/** Private, defaults to 20 for 72 DPI setting. */
short widget_unit;

View File

@@ -4833,6 +4833,16 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"overlay while animation is played back");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "playback_fps_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, nullptr, "playback_fps_samples");
RNA_def_property_range(prop, 0, 200);
RNA_def_property_ui_text(
prop,
"FPS Average Samples",
"The number of frames to use for calculating FPS average. "
"Zero to calculate this automatically, where the number of samples matches the target FPS");
RNA_def_property_update(prop, 0, "rna_userdef_update");
USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(