diff options
author | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-08-20 15:29:05 +0300 |
---|---|---|
committer | Kévin Dietrich <kevin.dietrich@mailoo.org> | 2021-08-20 15:34:43 +0300 |
commit | 9bfc47c9334bc4fbecbe7871fff9af4cc46c8832 (patch) | |
tree | 40b56b036e4974111c7c9f0cf2ffe338a45053d8 /intern/cycles | |
parent | accf3045be40433045c197cfcdbcbc32a7724403 (diff) |
Alembic Procedural: basic cache control settings
This adds a setting to enable data caching, and another one to set the
maximum cache size in megabytes.
When caching is enabled we load the data for the entire animation in
memory, as we already do, however, if the data exceeds the memory limit,
render is aborted.
When caching is disabled, we simply load the data for the current frame
in memory.
Ref D10197
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D11163
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/blender/blender_object.cpp | 3 | ||||
-rw-r--r-- | intern/cycles/render/alembic.cpp | 70 | ||||
-rw-r--r-- | intern/cycles/render/alembic.h | 30 | ||||
-rw-r--r-- | intern/cycles/render/alembic_read.cpp | 16 |
4 files changed, 116 insertions, 3 deletions
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 2dbebac4cc3..a7eae421b55 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -523,6 +523,9 @@ void BlenderSync::sync_procedural(BL::Object &b_ob, procedural->set_scale(cache_file.scale()); + procedural->set_use_prefetch(cache_file.use_prefetch()); + procedural->set_prefetch_cache_size(cache_file.prefetch_cache_size()); + /* create or update existing AlembicObjects */ ustring object_path = ustring(b_mesh_cache.object_path()); diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 81f47256739..69bc0712674 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -25,6 +25,7 @@ #include "render/shader.h" #include "util/util_foreach.h" +#include "util/util_logging.h" #include "util/util_progress.h" #include "util/util_transform.h" #include "util/util_vector.h" @@ -211,6 +212,35 @@ void CachedData::set_time_sampling(TimeSampling time_sampling) } } +size_t CachedData::memory_used() const +{ + size_t mem_used = 0; + + mem_used += curve_first_key.memory_used(); + mem_used += curve_keys.memory_used(); + mem_used += curve_radius.memory_used(); + mem_used += curve_shader.memory_used(); + mem_used += num_ngons.memory_used(); + mem_used += shader.memory_used(); + mem_used += subd_creases_edge.memory_used(); + mem_used += subd_creases_weight.memory_used(); + mem_used += subd_face_corners.memory_used(); + mem_used += subd_num_corners.memory_used(); + mem_used += subd_ptex_offset.memory_used(); + mem_used += subd_smooth.memory_used(); + mem_used += subd_start_corner.memory_used(); + mem_used += transforms.memory_used(); + mem_used += triangles.memory_used(); + mem_used += uv_loops.memory_used(); + mem_used += vertices.memory_used(); + + for (const CachedAttribute &attr : attributes) { + mem_used += attr.data.memory_used(); + } + + return mem_used; +} + static M44d convert_yup_zup(const M44d &mtx, float scale_mult) { V3d scale, shear, rotation, translation; @@ -706,6 +736,9 @@ NODE_DEFINE(AlembicProcedural) SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type()); + SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true); + SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096); + return type; } @@ -823,6 +856,30 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) } } + if (use_prefetch_is_modified()) { + if (!use_prefetch) { + for (Node *node : objects) { + AlembicObject *object = static_cast<AlembicObject *>(node); + object->clear_cache(); + } + } + } + + if (prefetch_cache_size_is_modified()) { + /* Check whether the current memory usage fits in the new requested size, + * abort the render if it is any higher. */ + size_t memory_used = 0ul; + for (Node *node : objects) { + AlembicObject *object = static_cast<AlembicObject *>(node); + memory_used += object->get_cached_data().memory_used(); + } + + if (memory_used > get_prefetch_cache_size_in_bytes()) { + progress.set_error("Error: Alembic Procedural memory limit reached"); + return; + } + } + build_caches(progress); foreach (Node *node, objects) { @@ -1300,6 +1357,8 @@ void AlembicProcedural::walk_hierarchy( void AlembicProcedural::build_caches(Progress &progress) { + size_t memory_used = 0; + for (Node *node : objects) { AlembicObject *object = static_cast<AlembicObject *>(node); @@ -1353,7 +1412,18 @@ void AlembicProcedural::build_caches(Progress &progress) if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) { object->setup_transform_cache(object->get_cached_data(), scale); } + + memory_used += object->get_cached_data().memory_used(); + + if (use_prefetch) { + if (memory_used > get_prefetch_cache_size_in_bytes()) { + progress.set_error("Error: Alembic Procedural memory limit reached"); + return; + } + } } + + VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 9c58af720f6..8e166a5ab04 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -272,6 +272,21 @@ template<typename T> class DataStore { node->set(*socket, value); } + size_t memory_used() const + { + if constexpr (is_array<T>::value) { + size_t mem_used = 0; + + for (const T &array : data) { + mem_used += array.size() * sizeof(array[0]); + } + + return mem_used; + } + + return data.size() * sizeof(T); + } + private: const TimeIndexPair &get_index_for_time(double time) const { @@ -332,6 +347,8 @@ struct CachedData { void invalidate_last_loaded_time(bool attributes_only = false); void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling); + + size_t memory_used() const; }; /* Representation of an Alembic object for the AlembicProcedural. @@ -482,6 +499,13 @@ class AlembicProcedural : public Procedural { * software. */ NODE_SOCKET_API(float, scale) + /* Cache controls */ + NODE_SOCKET_API(bool, use_prefetch) + + /* Memory limit for the cache, if the data does not fit within this limit, rendering is aborted. + */ + NODE_SOCKET_API(int, prefetch_cache_size) + AlembicProcedural(); ~AlembicProcedural(); @@ -531,6 +555,12 @@ class AlembicProcedural : public Procedural { void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time); void build_caches(Progress &progress); + + size_t get_prefetch_cache_size_in_bytes() const + { + /* prefetch_cache_size is in megabytes, so convert to bytes. */ + return static_cast<size_t>(prefetch_cache_size) * 1024 * 1024; + } }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/alembic_read.cpp b/intern/cycles/render/alembic_read.cpp index c53ec668938..b105af63b44 100644 --- a/intern/cycles/render/alembic_read.cpp +++ b/intern/cycles/render/alembic_read.cpp @@ -44,9 +44,19 @@ static set<chrono_t> get_relevant_sample_times(AlembicProcedural *proc, return result; } - // load the data for the entire animation - const double start_frame = static_cast<double>(proc->get_start_frame()); - const double end_frame = static_cast<double>(proc->get_end_frame()); + double start_frame; + double end_frame; + + if (proc->get_use_prefetch()) { + // load the data for the entire animation + start_frame = static_cast<double>(proc->get_start_frame()); + end_frame = static_cast<double>(proc->get_end_frame()); + } + else { + // load the data for the current frame + start_frame = static_cast<double>(proc->get_frame()); + end_frame = start_frame; + } const double frame_rate = static_cast<double>(proc->get_frame_rate()); const double start_time = start_frame / frame_rate; |