Animation: Refactor storage usage during fcurve modifier evaluation
authorJacques Lucke <mail@jlucke.com>
Wed, 17 Apr 2019 16:09:33 +0000 (18:09 +0200)
committerJacques Lucke <mail@jlucke.com>
Wed, 17 Apr 2019 16:09:33 +0000 (18:09 +0200)
Previously, when a fcurve modifier used storage,
many heap allocations were done.
This caused major slowdowns as described in T63656.

Furthermore, the storage usage was a special case only
used by the Cycles modifier. This refactor makes
storage usage the "normal" case.
That reduces the overall complexity.

The storage is stack allocated now.

The framerate on the provided test scene went up from ~5 fps to ~16 fps.

Reviewers: angavrilov

Differential Revision: https://developer.blender.org/D4701

source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/fmodifier.c

index 52a4d00b1176199d1c5ac78b48598558cd4d562f..5e45faf1d0b11e277a04ea838f0c8df2324b9033 100644 (file)
@@ -115,8 +115,6 @@ float evaluate_driver(struct PathResolvedRNA *anim_rna,
 
 /* ************** F-Curve Modifiers *************** */
 
-typedef struct GHash FModifierStackStorage;
-
 /* F-Curve Modifier Type-Info (fmi):
  *  This struct provides function pointers for runtime, so that functions can be
  *  written more generally (with fewer/no special exceptions for various modifiers).
@@ -136,6 +134,7 @@ typedef struct FModifierTypeInfo {
   short requires;      /* eFMI_Requirement_Flags */
   char name[64];       /* name of modifier in interface */
   char structName[64]; /* name of struct for SDNA */
+  uint storage_size;   /* size of buffer that can be reused between time and value evaluation */
 
   /* data management function pointers - special handling */
   /* free any data that is allocated separately (optional) */
@@ -149,27 +148,11 @@ typedef struct FModifierTypeInfo {
 
   /* evaluation */
   /* evaluate time that the modifier requires the F-Curve to be evaluated at */
-  float (*evaluate_modifier_time)(struct FCurve *fcu,
-                                  struct FModifier *fcm,
-                                  float cvalue,
-                                  float evaltime);
+  float (*evaluate_modifier_time)(
+      struct FCurve *fcu, struct FModifier *fcm, float cvalue, float evaltime, void *storage);
   /* evaluate the modifier for the given time and 'accumulated' value */
-  void (*evaluate_modifier)(struct FCurve *fcu,
-                            struct FModifier *fcm,
-                            float *cvalue,
-                            float evaltime);
-
-  /* Same as above but for modifiers which requires storage */
-  float (*evaluate_modifier_time_storage)(FModifierStackStorage *storage,
-                                          struct FCurve *fcu,
-                                          struct FModifier *fcm,
-                                          float cvalue,
-                                          float evaltime);
-  void (*evaluate_modifier_storage)(FModifierStackStorage *storage,
-                                    struct FCurve *fcu,
-                                    struct FModifier *fcm,
-                                    float *cvalue,
-                                    float evaltime);
+  void (*evaluate_modifier)(
+      struct FCurve *fcu, struct FModifier *fcm, float *cvalue, float evaltime, void *storage);
 } FModifierTypeInfo;
 
 /* Values which describe the behavior of a FModifier Type */
@@ -194,9 +177,6 @@ typedef enum eFMI_Requirement_Flags {
   FMI_REQUIRES_NOTHING = (1 << 1),
   /* refer to modifier instance */
   FMI_REQUIRES_RUNTIME_CHECK = (1 << 2),
-
-  /* Requires to store data shared between time and valua evaluation */
-  FMI_REQUIRES_STORAGE = (1 << 3),
 } eFMI_Requirement_Flags;
 
 /* Function Prototypes for FModifierTypeInfo's */
@@ -216,14 +196,19 @@ void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
 
 bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
 
-FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers);
-void evaluate_fmodifiers_storage_free(FModifierStackStorage *storage);
-float evaluate_time_fmodifiers(FModifierStackStorage *storage,
+typedef struct FModifiersStackStorage {
+  uint modifier_count;
+  uint size_per_modifier;
+  void *buffer;
+} FModifiersStackStorage;
+
+uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers);
+float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
                                ListBase *modifiers,
                                struct FCurve *fcu,
                                float cvalue,
                                float evaltime);
-void evaluate_value_fmodifiers(FModifierStackStorage *storage,
+void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
                                ListBase *modifiers,
                                struct FCurve *fcu,
                                float *cvalue,
index 75244a8ba8a8126b6b67b4793b50a31d53f1baaf..de92077b0527ca8e0c1fef6d6b09ef5225e575fd 100644 (file)
@@ -2965,7 +2965,6 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
                                          NlaEvalStrip *nes,
                                          NlaEvalSnapshot *snapshot)
 {
-  FModifierStackStorage *storage;
   ListBase tmp_modifiers = {NULL, NULL};
   NlaStrip *strip = nes->strip;
   FCurve *fcu;
@@ -2986,8 +2985,12 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
   nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
 
   /* evaluate strip's modifiers which modify time to evaluate the base curves at */
-  storage = evaluate_fmodifiers_storage_new(&tmp_modifiers);
-  evaltime = evaluate_time_fmodifiers(storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time);
+  FModifiersStackStorage storage;
+  storage.modifier_count = BLI_listbase_count(&tmp_modifiers);
+  storage.size_per_modifier = evaluate_fmodifiers_storage_size_per_modifier(&tmp_modifiers);
+  storage.buffer = alloca(storage.modifier_count * storage.size_per_modifier);
+
+  evaltime = evaluate_time_fmodifiers(&storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time);
 
   NlaBlendData blend = {
       .snapshot = snapshot,
@@ -3013,7 +3016,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
     /* apply strip's F-Curve Modifiers on this value
      * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
      */
-    evaluate_value_fmodifiers(storage, &tmp_modifiers, fcu, &value, strip->strip_time);
+    evaluate_value_fmodifiers(&storage, &tmp_modifiers, fcu, &value, strip->strip_time);
 
     /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
      * stored in this channel if it has been used already
@@ -3025,9 +3028,6 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
 
   nlaeval_blend_flush(&blend);
 
-  /* free temporary storage */
-  evaluate_fmodifiers_storage_free(storage);
-
   /* unlink this strip's modifiers from the parent's modifiers again */
   nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
 }
index 4a2a610918ca959f87269125437a1617c5509b4d..f93a5e658458bbd8fa15da1b4db618988cb694d9 100644 (file)
@@ -2851,12 +2851,15 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
  */
 static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue)
 {
-  FModifierStackStorage *storage;
   float devaltime;
 
   /* evaluate modifiers which modify time to evaluate the base curve at */
-  storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
-  devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
+  FModifiersStackStorage storage;
+  storage.modifier_count = BLI_listbase_count(&fcu->modifiers);
+  storage.size_per_modifier = evaluate_fmodifiers_storage_size_per_modifier(&fcu->modifiers);
+  storage.buffer = alloca(storage.modifier_count * storage.size_per_modifier);
+
+  devaltime = evaluate_time_fmodifiers(&storage, &fcu->modifiers, fcu, cvalue, evaltime);
 
   /* evaluate curve-data
    * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
@@ -2868,9 +2871,7 @@ static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue)
     cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
 
   /* evaluate modifiers */
-  evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
-
-  evaluate_fmodifiers_storage_free(storage);
+  evaluate_value_fmodifiers(&storage, &fcu->modifiers, fcu, &cvalue, devaltime);
 
   /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
    * here so that the curve can be sampled correctly
index 3cecfb8aa174d70b37a12e0669aa4c51073b71c5..3cb941e1f93fd567e033a9c6729e48c1e8d1f8b3 100644 (file)
@@ -48,11 +48,6 @@ static CLG_LogRef LOG = {"bke.fmodifier"};
 
 /* ******************************** F-Modifiers ********************************* */
 
-/* Forward declarations. */
-void fmodifiers_storage_put(FModifierStackStorage *storage, FModifier *fcm, void *data);
-void fmodifiers_storage_remove(FModifierStackStorage *storage, FModifier *fcm);
-void *fmodifiers_storage_get(FModifierStackStorage *storage, FModifier *fcm);
-
 /* Info ------------------------------- */
 
 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
@@ -75,7 +70,7 @@ void *fmodifiers_storage_get(FModifierStackStorage *storage, FModifier *fcm);
  *   for such cases, just use NULL
  * - these should be defined after all the functions have been defined, so that
  *   forward-definitions/prototypes don't need to be used!
- * - keep this copy #if-def'd so that future constraints can get based off this
+ * - keep this copy #if-def'd so that future modifier can get based off this
  */
 #if 0
 static FModifierTypeInfo FMI_MODNAME = {
@@ -85,6 +80,7 @@ static FModifierTypeInfo FMI_MODNAME = {
     FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
     "Modifier Name",               /* name */
     "FMod_ModName",                /* struct name */
+    0,                             /* storage size */
     fcm_modname_free,              /* free data */
     fcm_modname_relink,            /* relink data */
     fcm_modname_copy,              /* copy data */
@@ -92,8 +88,6 @@ static FModifierTypeInfo FMI_MODNAME = {
     fcm_modname_verify,            /* verify */
     fcm_modname_time,              /* evaluate time */
     fcm_modname_evaluate,          /* evaluate */
-    fcm_modname_time_storage,      /* evaluate time with storage */
-    fcm_modname_evaluate_storage,  /* evaluate with storage */
 };
 #endif
 
@@ -166,10 +160,8 @@ static void fcm_generator_verify(FModifier *fcm)
   }
 }
 
-static void fcm_generator_evaluate(FCurve *UNUSED(fcu),
-                                   FModifier *fcm,
-                                   float *cvalue,
-                                   float evaltime)
+static void fcm_generator_evaluate(
+    FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
 {
   FMod_Generator *data = (FMod_Generator *)fcm->data;
 
@@ -241,14 +233,13 @@ static FModifierTypeInfo FMI_GENERATOR = {
     FMI_REQUIRES_NOTHING,     /* requirements */
     N_("Generator"),          /* name */
     "FMod_Generator",         /* struct name */
+    0,                        /* storage size */
     fcm_generator_free,       /* free data */
     fcm_generator_copy,       /* copy data */
     fcm_generator_new_data,   /* new data */
     fcm_generator_verify,     /* verify */
     NULL,                     /* evaluate time */
     fcm_generator_evaluate,   /* evaluate */
-    NULL,                     /* evaluate time with storage */
-    NULL,                     /* evaluate with storage */
 };
 
 /* Built-In Function Generator F-Curve Modifier --------------------------- */
@@ -284,10 +275,8 @@ static double sinc(double x)
     return sin(M_PI * x) / (M_PI * x);
 }
 
-static void fcm_fn_generator_evaluate(FCurve *UNUSED(fcu),
-                                      FModifier *fcm,
-                                      float *cvalue,
-                                      float evaltime)
+static void fcm_fn_generator_evaluate(
+    FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
 {
   FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
   double arg = data->phase_multiplier * evaltime + data->phase_offset;
@@ -367,14 +356,13 @@ static FModifierTypeInfo FMI_FN_GENERATOR = {
     FMI_REQUIRES_NOTHING,           /* requirements */
     N_("Built-In Function"),        /* name */
     "FMod_FunctionGenerator",       /* struct name */
+    0,                              /* storage size */
     NULL,                           /* free data */
     NULL,                           /* copy data */
     fcm_fn_generator_new_data,      /* new data */
     NULL,                           /* verify */
     NULL,                           /* evaluate time */
     fcm_fn_generator_evaluate,      /* evaluate */
-    NULL,                           /* evaluate time with storage */
-    NULL,                           /* evaluate with storage */
 };
 
 /* Envelope F-Curve Modifier --------------------------- */
@@ -417,10 +405,8 @@ static void fcm_envelope_verify(FModifier *fcm)
   }
 }
 
-static void fcm_envelope_evaluate(FCurve *UNUSED(fcu),
-                                  FModifier *fcm,
-                                  float *cvalue,
-                                  float evaltime)
+static void fcm_envelope_evaluate(
+    FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
 {
   FMod_Envelope *env = (FMod_Envelope *)fcm->data;
   FCM_EnvelopeData *fed, *prevfed, *lastfed;
@@ -480,14 +466,13 @@ static FModifierTypeInfo FMI_ENVELOPE = {
     0,                       /* requirements */
     N_("Envelope"),          /* name */
     "FMod_Envelope",         /* struct name */
+    0,                       /* storage size */
     fcm_envelope_free,       /* free data */
     fcm_envelope_copy,       /* copy data */
     fcm_envelope_new_data,   /* new data */
     fcm_envelope_verify,     /* verify */
     NULL,                    /* evaluate time */
     fcm_envelope_evaluate,   /* evaluate */
-    NULL,                    /* evaluate time with storage */
-    NULL,                    /* evaluate with storage */
 };
 
 /* exported function for finding points */
@@ -610,18 +595,19 @@ static void fcm_cycles_new_data(void *mdata)
   data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
 }
 
-static float fcm_cycles_time(FModifierStackStorage *storage,
-                             FCurve *fcu,
-                             FModifier *fcm,
-                             float UNUSED(cvalue),
-                             float evaltime)
+static float fcm_cycles_time(
+    FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime, void *storage_)
 {
   FMod_Cycles *data = (FMod_Cycles *)fcm->data;
+  tFCMED_Cycles *storage = storage_;
   float prevkey[2], lastkey[2], cycyofs = 0.0f;
   short side = 0, mode = 0;
   int cycles = 0;
   float ofs = 0;
 
+  /* Initialize storage. */
+  storage->cycyofs = 0;
+
   /* check if modifier is first in stack, otherwise disable ourself... */
   /* FIXME... */
   if (fcm->prev) {
@@ -745,53 +731,37 @@ static float fcm_cycles_time(FModifierStackStorage *storage,
 
   /* store temp data if needed */
   if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
-    tFCMED_Cycles *edata;
-
-    /* for now, this is just a float, but we could get more stuff... */
-    edata = MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
-    edata->cycyofs = cycyofs;
-
-    fmodifiers_storage_put(storage, fcm, edata);
+    storage->cycyofs = cycyofs;
   }
 
   /* return the new frame to evaluate */
   return evaltime;
 }
 
-static void fcm_cycles_evaluate(FModifierStackStorage *storage,
-                                FCurve *UNUSED(fcu),
-                                FModifier *fcm,
+static void fcm_cycles_evaluate(FCurve *UNUSED(fcu),
+                                FModifier *UNUSED(fcm),
                                 float *cvalue,
-                                float UNUSED(evaltime))
+                                float UNUSED(evaltime),
+                                void *storage_)
 {
-  tFCMED_Cycles *edata = fmodifiers_storage_get(storage, fcm);
-
-  /* use temp data */
-  if (edata) {
-    /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
-    *cvalue += edata->cycyofs;
-
-    /* free temp data */
-    MEM_freeN(edata);
-    fmodifiers_storage_remove(storage, fcm);
-  }
+  tFCMED_Cycles *storage = storage_;
+  *cvalue += storage->cycyofs;
 }
 
 static FModifierTypeInfo FMI_CYCLES = {
-    FMODIFIER_TYPE_CYCLES,                             /* type */
-    sizeof(FMod_Cycles),                               /* size */
-    FMI_TYPE_EXTRAPOLATION,                            /* action type */
-    FMI_REQUIRES_ORIGINAL_DATA | FMI_REQUIRES_STORAGE, /* requirements */
-    N_("Cycles"),                                      /* name */
-    "FMod_Cycles",                                     /* struct name */
-    NULL,                                              /* free data */
-    NULL,                                              /* copy data */
-    fcm_cycles_new_data,                               /* new data */
-    NULL /*fcm_cycles_verify*/,                        /* verify */
-    NULL,                                              /* evaluate time */
-    NULL,                                              /* evaluate */
-    fcm_cycles_time,                                   /* evaluate time with storage */
-    fcm_cycles_evaluate,                               /* evaluate with storage */
+    FMODIFIER_TYPE_CYCLES,      /* type */
+    sizeof(FMod_Cycles),        /* size */
+    FMI_TYPE_EXTRAPOLATION,     /* action type */
+    FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
+    N_("Cycles"),               /* name */
+    "FMod_Cycles",              /* struct name */
+    sizeof(tFCMED_Cycles),      /* storage size */
+    NULL,                       /* free data */
+    NULL,                       /* copy data */
+    fcm_cycles_new_data,        /* new data */
+    NULL /*fcm_cycles_verify*/, /* verify */
+    fcm_cycles_time,            /* evaluate time */
+    fcm_cycles_evaluate,        /* evaluate */
 };
 
 /* Noise F-Curve Modifier  --------------------------- */
@@ -809,7 +779,8 @@ static void fcm_noise_new_data(void *mdata)
   data->modification = FCM_NOISE_MODIF_REPLACE;
 }
 
-static void fcm_noise_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_noise_evaluate(
+    FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime, void *UNUSED(storage))
 {
   FMod_Noise *data = (FMod_Noise *)fcm->data;
   float noise;
@@ -845,14 +816,13 @@ static FModifierTypeInfo FMI_NOISE = {
     0,                         /* requirements */
     N_("Noise"),               /* name */
     "FMod_Noise",              /* struct name */
+    0,                         /* storage size */
     NULL,                      /* free data */
     NULL,                      /* copy data */
     fcm_noise_new_data,        /* new data */
     NULL /*fcm_noise_verify*/, /* verify */
     NULL,                      /* evaluate time */
     fcm_noise_evaluate,        /* evaluate */
-    NULL,                      /* evaluate time with storage */
-    NULL,                      /* evaluate with storage */
 };
 
 /* Python F-Curve Modifier --------------------------- */
@@ -886,7 +856,8 @@ static void fcm_python_copy(FModifier *fcm, const FModifier *src)
 static void fcm_python_evaluate(FCurve *UNUSED(fcu),
                                 FModifier *UNUSED(fcm),
                                 float *UNUSED(cvalue),
-                                float UNUSED(evaltime))
+                                float UNUSED(evaltime),
+                                void *UNUSED(storage))
 {
 #ifdef WITH_PYTHON
   //FMod_Python *data = (FMod_Python *)fcm->data;
@@ -904,14 +875,13 @@ static FModifierTypeInfo FMI_PYTHON = {
     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
     N_("Python"),               /* name */
     "FMod_Python",              /* struct name */
+    0,                          /* storage size */
     fcm_python_free,            /* free data */
     fcm_python_copy,            /* copy data */
     fcm_python_new_data,        /* new data */
     NULL /*fcm_python_verify*/, /* verify */
     NULL /*fcm_python_time*/,   /* evaluate time */
     fcm_python_evaluate,        /* evaluate */
-    NULL,                       /* evaluate time with storage */
-    NULL,                       /* evaluate with storage */
 };
 
 /* Limits F-Curve Modifier --------------------------- */
@@ -919,7 +889,8 @@ static FModifierTypeInfo FMI_PYTHON = {
 static float fcm_limits_time(FCurve *UNUSED(fcu),
                              FModifier *fcm,
                              float UNUSED(cvalue),
-                             float evaltime)
+                             float evaltime,
+                             void *UNUSED(storage))
 {
   FMod_Limits *data = (FMod_Limits *)fcm->data;
 
@@ -936,7 +907,8 @@ static float fcm_limits_time(FCurve *UNUSED(fcu),
 static void fcm_limits_evaluate(FCurve *UNUSED(fcu),
                                 FModifier *fcm,
                                 float *cvalue,
-                                float UNUSED(evaltime))
+                                float UNUSED(evaltime),
+                                void *UNUSED(storage))
 {
   FMod_Limits *data = (FMod_Limits *)fcm->data;
 
@@ -955,14 +927,13 @@ static FModifierTypeInfo FMI_LIMITS = {
     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
     N_("Limits"),               /* name */
     "FMod_Limits",              /* struct name */
+    0,                          /* storage size */
     NULL,                       /* free data */
     NULL,                       /* copy data */
     NULL,                       /* new data */
     NULL,                       /* verify */
     fcm_limits_time,            /* evaluate time */
     fcm_limits_evaluate,        /* evaluate */
-    NULL,                       /* evaluate time with storage */
-    NULL,                       /* evaluate with storage */
 };
 
 /* Stepped F-Curve Modifier --------------------------- */
@@ -979,7 +950,8 @@ static void fcm_stepped_new_data(void *mdata)
 static float fcm_stepped_time(FCurve *UNUSED(fcu),
                               FModifier *fcm,
                               float UNUSED(cvalue),
-                              float evaltime)
+                              float evaltime,
+                              void *UNUSED(storage))
 {
   FMod_Stepped *data = (FMod_Stepped *)fcm->data;
   int snapblock;
@@ -1014,14 +986,13 @@ static FModifierTypeInfo FMI_STEPPED = {
     FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
     N_("Stepped"),              /* name */
     "FMod_Stepped",             /* struct name */
+    0,                          /* storage size */
     NULL,                       /* free data */
     NULL,                       /* copy data */
     fcm_stepped_new_data,       /* new data */
     NULL,                       /* verify */
     fcm_stepped_time,           /* evaluate time */
     NULL,                       /* evaluate */
-    NULL,                       /* evaluate time with storage */
-    NULL,                       /* evaluate with storage */
 };
 
 /* F-Curve Modifier API --------------------------- */
@@ -1313,57 +1284,26 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
 
 /* Evaluation API --------------------------- */
 
-FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers)
+uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers)
 {
-  FModifier *fcm;
-
   /* Sanity checks. */
-  if (ELEM(NULL, modifiers, modifiers->last)) {
-    return NULL;
+  if (ELEM(NULL, modifiers, modifiers->first)) {
+    return 0;
   }
 
-  for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
+  uint max_size = 0;
+
+  for (FModifier *fcm = modifiers->first; fcm; fcm = fcm->next) {
     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
 
     if (fmi == NULL) {
       continue;
     }
 
-    if (fmi->requires & FMI_REQUIRES_STORAGE) {
-      return (FModifierStackStorage *)BLI_ghash_new(
-          BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "fmodifier stack temp storage");
-    }
-  }
-
-  return NULL;
-}
-
-void evaluate_fmodifiers_storage_free(FModifierStackStorage *storage)
-{
-  if (storage != NULL) {
-    BLI_ghash_free((GHash *)storage, NULL, NULL);
+    max_size = MAX2(max_size, fmi->storage_size);
   }
-}
-
-void fmodifiers_storage_put(FModifierStackStorage *storage, FModifier *fcm, void *data)
-{
-  BLI_assert(storage != NULL);
-
-  BLI_ghash_insert((GHash *)storage, fcm, data);
-}
-
-void fmodifiers_storage_remove(FModifierStackStorage *storage, FModifier *fcm)
-{
-  BLI_assert(storage != NULL);
-
-  BLI_ghash_remove((GHash *)storage, fcm, NULL, NULL);
-}
-
-void *fmodifiers_storage_get(FModifierStackStorage *storage, FModifier *fcm)
-{
-  BLI_assert(storage != NULL);
 
-  return BLI_ghash_lookup((GHash *)storage, fcm);
+  return max_size;
 }
 
 /* helper function - calculate influence of FModifier */
@@ -1418,11 +1358,12 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
  *
  * Note: *fcu might be NULL
  */
-float evaluate_time_fmodifiers(
-    FModifierStackStorage *storage, ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
+float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
+                               ListBase *modifiers,
+                               FCurve *fcu,
+                               float cvalue,
+                               float evaltime)
 {
-  FModifier *fcm;
-
   /* sanity checks */
   if (ELEM(NULL, modifiers, modifiers->last))
     return evaltime;
@@ -1440,7 +1381,8 @@ float evaluate_time_fmodifiers(
    * effect, which should get us the desired effects when using layered time manipulations
    * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
    */
-  for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
+  uint fcm_index = storage->modifier_count - 1;
+  for (FModifier *fcm = modifiers->last; fcm; fcm = fcm->prev, fcm_index--) {
     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
 
     if (fmi == NULL)
@@ -1452,18 +1394,14 @@ float evaluate_time_fmodifiers(
     if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
         ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
       /* only evaluate if there's a callback for this */
-      if (fmi->evaluate_modifier_time || fmi->evaluate_modifier_time_storage) {
+      if (fmi->evaluate_modifier_time) {
         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
-          float influence = eval_fmodifier_influence(fcm, evaltime);
-          float nval;
+          void *storage_ptr = POINTER_OFFSET(storage->buffer,
+                                             fcm_index * storage->size_per_modifier);
 
-          if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
-            nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
-          }
-          else {
-            nval = fmi->evaluate_modifier_time_storage(storage, fcu, fcm, cvalue, evaltime);
-          }
+          float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime, storage_ptr);
 
+          float influence = eval_fmodifier_influence(fcm, evaltime);
           evaltime = interpf(nval, evaltime, influence);
         }
       }
@@ -1477,7 +1415,7 @@ float evaluate_time_fmodifiers(
 /* Evaluates the given set of F-Curve Modifiers using the given data
  * Should only be called after evaluate_time_fmodifiers() has been called...
  */
-void evaluate_value_fmodifiers(FModifierStackStorage *storage,
+void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
                                ListBase *modifiers,
                                FCurve *fcu,
                                float *cvalue,
@@ -1493,7 +1431,8 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage,
     return;
 
   /* evaluate modifiers */
-  for (fcm = modifiers->first; fcm; fcm = fcm->next) {
+  uint fcm_index = 0;
+  for (fcm = modifiers->first; fcm; fcm = fcm->next, fcm_index++) {
     const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
 
     if (fmi == NULL)
@@ -1502,18 +1441,15 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage,
     /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
     if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
         ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
-      if (fmi->evaluate_modifier || fmi->evaluate_modifier_storage) {
+      if (fmi->evaluate_modifier) {
         if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
-          float influence = eval_fmodifier_influence(fcm, evaltime);
-          float nval = *cvalue;
+          void *storage_ptr = POINTER_OFFSET(storage->buffer,
+                                             fcm_index * storage->size_per_modifier);
 
-          if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
-            fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
-          }
-          else {
-            fmi->evaluate_modifier_storage(storage, fcu, fcm, &nval, evaltime);
-          }
+          float nval = *cvalue;
+          fmi->evaluate_modifier(fcu, fcm, &nval, evaltime, storage_ptr);
 
+          float influence = eval_fmodifier_influence(fcm, evaltime);
           *cvalue = interpf(nval, *cvalue, influence);
         }
       }