[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