[Bf-blender-cvs] [bb732c240de] geometry-nodes-simulation: Half finished refactoring to simulation cache

Hans Goudey noreply at git.blender.org
Sun Dec 4 22:06:38 CET 2022


Commit: bb732c240de0d9930c90168fd24dfeab11076d44
Author: Hans Goudey
Date:   Sun Dec 4 15:06:28 2022 -0600
Branches: geometry-nodes-simulation
https://developer.blender.org/rBbb732c240de0d9930c90168fd24dfeab11076d44

Half finished refactoring to simulation cache

- Cache is accessed with a string identifier, allowing multiple sockets in the future
- Cache is meant to be stored in a simple array, not sparsely like before
- Persistent cache and temporary "last run" cache are separated more clearly
- Use a "Time Point" class instead of integers, to maybe clarify adding subframe support in the future
- Use a different "sim" namespace (not sure if that will last)
- The value from the last frame is moved, to avoid a copy when no persistent cache is used

I don't think this works now, at least I haven't tested it.

===================================================================

M	source/blender/blenkernel/BKE_compute_cache.hh
M	source/blender/makesdna/DNA_modifier_types.h
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/NOD_geometry_nodes_lazy_function.hh
M	source/blender/nodes/geometry/nodes/node_geo_simulation_input.cc
M	source/blender/nodes/geometry/nodes/node_geo_simulation_output.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_compute_cache.hh b/source/blender/blenkernel/BKE_compute_cache.hh
index 8af09d96618..0eadf08ad7f 100644
--- a/source/blender/blenkernel/BKE_compute_cache.hh
+++ b/source/blender/blenkernel/BKE_compute_cache.hh
@@ -9,108 +9,185 @@
 
 #include "BKE_geometry_set.hh"
 
-namespace blender::bke {
+namespace blender::bke::sim {
 
-struct GeometryCacheValue {
+/* TODO: Take into account subframes. But do we make caches for subframes? Probably not. */
+struct TimePoint {
   int frame;
   float time;
-  GeometrySet geometry_set;
+
+  uint64_t hash()
+  {
+    return get_default_hash(this->frame);
+  }
+
+  friend bool operator==(const TimePoint &a, const TimePoint &b)
+  {
+    return a.frame == b.frame;
+  }
 };
 
 /* TODO: Clear cache when editing nodes? Only sometimes, when persistent caching is turned off. */
-struct SimulationCache {
-  Vector<GeometryCacheValue> geometry_per_frame;
+class SimulationCache {
+
+  struct CacheValues {
+    /* TODO: This will need to be a generic value at some point. */
+    /* Map from simulation time index (see #SimulationCache::times) to value. */
+    Vector<GeometrySet> persistent_cache;
+
+    std::optional<GeometrySet> non_persistent_value;
+
+    GeometrySet lookup_index(const int index) const
+    {
+      if (!persistent_cache.index_range().contains(index)) {
+        return persistent_cache[index];
+      }
+      return {};
+    }
+  };
+
+  /* Map from cache data identifier (socket name) to values at stored times. */
+  Map<std::string, CacheValues> caches_;
+
+  /* Ordered list of cached simulation frames. */
+  Vector<TimePoint> persistent_times_;
+
+  std::optional<TimePoint> start_time_;
+
+  std::optional<TimePoint> last_run_time_;
+
+ public:
+  std::optional<TimePoint> start_time() const
+  {
+    return start_time_;
+  }
+  std::optional<TimePoint> last_run_time() const
+  {
+    return last_run_time_;
+  }
 
-  const GeometryCacheValue *value_at_or_before_time(const int frame) const
+  std::optional<GeometrySet> value_at_or_before_time(StringRef data_name, TimePoint time)
   {
-    const int index = this->index_at_or_before_time(frame);
-    if (index >= geometry_per_frame.size()) {
-      return nullptr;
+    const CacheValues *values = caches_.lookup_ptr(data_name);
+    if (!values) {
+      return std::nullopt;
     }
-    return &geometry_per_frame[index];
+    if (last_run_time_->time < time.time) {
+      if (values->non_persistent_value) {
+        return std::move(values->non_persistent_value);
+      }
+    }
+    const int index = this->index_at_or_before_time(time);
+    if (!values->persistent_cache.index_range().contains(index)) {
+      return std::nullopt;
+    }
+    return values->persistent_cache[index];
   }
 
-  GeometryCacheValue *value_at_or_before_time(const int frame)
+  std::optional<GeometrySet> value_before_time(StringRef data_name, TimePoint time)
   {
-    const int index = this->index_at_or_before_time(frame);
-    if (index >= geometry_per_frame.size()) {
-      return nullptr;
+    const CacheValues *values = caches_.lookup_ptr(data_name);
+    if (!values) {
+      return std::nullopt;
+    }
+    if (last_run_time_->time < time.time) {
+      if (values->non_persistent_value) {
+        return std::move(values->non_persistent_value);
+      }
+    }
+    const int index = this->index_before_time(time);
+    if (!values->persistent_cache.index_range().contains(index)) {
+      return std::nullopt;
     }
-    return &geometry_per_frame[index];
+    return values->persistent_cache[index];
   }
 
-  const GeometryCacheValue *value_before_time(const int frame) const
+  std::optional<GeometrySet> value_at_time(StringRef data_name, TimePoint time)
   {
-    const int index = this->index_before_time(frame);
-    if (index >= geometry_per_frame.size()) {
-      return nullptr;
+    const CacheValues *values = caches_.lookup_ptr(data_name);
+    if (!values) {
+      return std::nullopt;
     }
-    return &geometry_per_frame[index];
+    const std::optional<int> index = this->index_at_time(time);
+    if (!index) {
+      return std::nullopt;
+    }
+    return values->persistent_cache[*index];
   }
 
-  GeometryCacheValue *value_at_time(const int frame)
+  void store_temporary(const StringRef data_name, const TimePoint time, GeometrySet value)
   {
-    for (const int i : geometry_per_frame.index_range()) {
-      if (geometry_per_frame[i].frame == frame) {
-        return &geometry_per_frame[i];
-      }
+    last_run_time_.emplace(time);
+    if (!start_time_) {
+      start_time_.emplace(time);
     }
-    return nullptr;
+    CacheValues &values = caches_.lookup_or_add_default_as(data_name);
+    values.non_persistent_value.emplace(std::move(value));
   }
 
-  GeometryCacheValue &value_at_time_ensure(const int frame)
+  void store_persistent(const StringRef data_name, const TimePoint time, GeometrySet value)
   {
-    for (const int i : geometry_per_frame.index_range()) {
-      if (geometry_per_frame[i].frame == frame) {
-        return geometry_per_frame[i];
-      }
+    last_run_time_.emplace(time);
+    if (!start_time_) {
+      start_time_.emplace(time);
     }
-    const int index = this->index_before_time(frame);
-    GeometryCacheValue value{};
-    geometry_per_frame.insert(index, value);
-    return geometry_per_frame[index];
+    const int index = this->index_before_time(time);
+    persistent_times_.resize(index);
+    persistent_times_[index] = time;
+    CacheValues &values = caches_.lookup_or_add_default_as(data_name);
+    values.persistent_cache.resize(index);
+    values.persistent_cache[index] = std::move(value);
   }
 
-  void insert(GeometrySet &geometry_set, const int frame, const float time)
+  void clear()
   {
-    BLI_assert(!this->value_at_time(frame));
-    GeometryCacheValue value{};
-    value.frame = frame;
-    value.time = time;
-    value.geometry_set = geometry_set;
-    const int index = this->index_before_time(frame);
-    geometry_per_frame.insert(index, value);
+    persistent_times_.clear();
+    caches_.clear();
+  }
+
+  bool is_empty() const
+  {
+    return persistent_times_.is_empty();
   }
 
  private:
-  int index_at_or_before_time(const int frame) const
+  int index_at_or_before_time(const TimePoint time) const
   {
-    if (geometry_per_frame.is_empty()) {
+    if (persistent_times_.is_empty()) {
       return 0;
     }
     int insert_index = 0;
-    for (const int i : geometry_per_frame.index_range()) {
-      if (geometry_per_frame[i].frame <= frame) {
+    for (const int i : persistent_times_.index_range()) {
+      if (persistent_times_[i].frame <= time.frame) {
         break;
       }
       insert_index++;
     }
     return insert_index;
   }
-  int index_before_time(const int frame) const
+  int index_before_time(const TimePoint time) const
   {
-    if (geometry_per_frame.is_empty()) {
+    if (persistent_times_.is_empty()) {
       return 0;
     }
     int insert_index = 0;
-    for (const int i : geometry_per_frame.index_range()) {
-      if (geometry_per_frame[i].frame < frame) {
+    for (const int i : persistent_times_.index_range()) {
+      if (persistent_times_[i].frame < time.frame) {
         break;
       }
       insert_index++;
     }
     return insert_index;
   }
+  std::optional<int> index_at_time(const TimePoint time) const
+  {
+    for (const int i : persistent_times_.index_range()) {
+      if (persistent_times_[i].frame == time.frame) {
+        return i;
+      }
+    }
+    return std::nullopt;
+  }
 };
 
 struct ComputeCaches {
@@ -125,6 +202,11 @@ struct ComputeCaches {
     cache_per_context = other.cache_per_context;
   }
 
+  SimulationCache *lookup_context(const ComputeContextHash &context_hash)
+  {
+    std::scoped_lock lock{mutex};
+    return cache_per_context.lookup_ptr(context_hash);
+  }
   const SimulationCache *lookup_context(const ComputeContextHash &context_hash) const
   {
     std::scoped_lock lock{mutex};
@@ -143,4 +225,4 @@ struct ComputeCaches {
   }
 };
 
-}  // namespace blender::bke
+}  // namespace blender::bke::sim
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 1cc91201975..978cbc1b749 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -11,10 +11,10 @@
 #include "DNA_session_uuid_types.h"
 
 #ifdef __cplusplus
-namespace blender::bke {
+namespace blender::bke::sim {
 struct ComputeCaches;
 }
-using ComputeCachesHandle = blender::bke::ComputeCaches;
+using ComputeCachesHandle = blender::bke::sim::ComputeCaches;
 #else
 typedef struct ComputeCachesHandle ComputeCachesHandle;
 #endif
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 171f0cf97d0..95b926ee172 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -1095,7 +1095,7 @@ static GeometrySet compute_geometry(
     const blender::nodes::GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
     const bNode &output_node,
     GeometrySet input_geometry_set,
-    blender::bke::ComputeCaches &compute_caches,
+    blender::bke::sim::ComputeCaches &compute_caches,
     NodesModifierData *nmd,
     const ModifierEvalContext *ctx)
 {
@@ -1295,7 +1295,7 @@ static void modifyGeometry(ModifierData *md,
   NodesModifierData *orig_nmd = reinterpret_cast<NodesModifierData *>(
       BKE_modifier_get_original(ctx->object, md));
   if (!orig_nmd->simulation_caches) {
-    orig_nmd->simulation_caches = new blender::bke::ComputeCaches();
+    orig_nmd->simulation_caches = new blender::bke::sim::ComputeCaches();
   }
 
   geometry_set = compute_geometry(tree,
@@ -1861,9 +1861,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
 
   tnmd->runtime_eval_log = nullptr;
   if (nmd->simulation_caches) {
-    const blender::bke::ComputeCaches &src_caches = *static_cast<blender::bke::ComputeCaches *>(
-        nmd->simulation_caches);
-    tnmd->simulation_caches = new blender::bke::ComputeCaches(src_caches);
+    const blender::bke::sim::ComputeCaches &src_caches =
+        *static_cast<blender::bke::sim::ComputeCac

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list