From b150b477202dc6d2a595b51be8cc34f8d6269731 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Aug 2023 19:22:05 +1000 Subject: [PATCH] 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. --- release/datafiles/userdef/userdef_default.c | 1 + scripts/startup/bl_ui/space_userpref.py | 3 + .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_userdef.cc | 4 ++ .../editors/include/ED_screen_types.hh | 12 ++-- source/blender/editors/screen/screen_edit.cc | 55 +++++++++++-------- source/blender/makesdna/DNA_userdef_types.h | 5 +- source/blender/makesrna/intern/rna_userdef.cc | 10 ++++ 8 files changed, 63 insertions(+), 29 deletions(-) diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index a2ce0d01d4b..b2bbad68670 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -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 diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index d8c6e8a6d6f..98d5fc43158 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -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() diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index dc90f595de7..b828c76d599 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -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 diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index 24dafa22e69..873db26bb65 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -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. * diff --git a/source/blender/editors/include/ED_screen_types.hh b/source/blender/editors/include/ED_screen_types.hh index 538e5e16fbf..70a017cd3a4 100644 --- a/source/blender/editors/include/ED_screen_types.hh +++ b/source/blender/editors/include/ED_screen_types.hh @@ -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]; }; /* ----------------------------------------------------- */ diff --git a/source/blender/editors/screen/screen_edit.cc b/source/blender/editors/screen/screen_edit.cc index eb3def4abbd..44e90ee7242 100644 --- a/source/blender/editors/screen/screen_edit.cc +++ b/source/blender/editors/screen/screen_edit.cc @@ -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(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(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( - scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo), __func__)); + scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo) + (sizeof(float) * redrawtimes_num), + __func__); + fpsi = static_cast(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; } diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index aff92efa3f4..99244835932 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index 50a2e75a6b0..24fbfc38c41 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -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(