From 8922d177c1019cc846928a3d5344991e000eeaa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 12 Mar 2021 01:57:41 +0100 Subject: Alembic procedural: specific result type for cache lookups This type, CacheLookupResult, holds the data for the current time, or an explanation as to why no data is available (already loaded, or simply nothing available). This is useful to document the behavior of the code but also, in future changes, to respond appropriately for missing data. --- intern/cycles/render/alembic.cpp | 29 ++++++++----- intern/cycles/render/alembic.h | 92 +++++++++++++++++++++++++++++++++++----- 2 files changed, 100 insertions(+), 21 deletions(-) (limited to 'intern') diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 59454eac8a5..0841a3c09cd 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -408,8 +408,10 @@ static void add_uvs(AlembicProcedural *proc, continue; } - const array *triangles = cached_data.triangles.data_for_time_no_check(time); - const array *triangles_loops = cached_data.triangles_loops.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); + const array *triangles_loops = + cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null(); if (!triangles || !triangles_loops) { continue; @@ -456,7 +458,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices, *normals.getTimeSampling()); attr.std = ATTR_STD_VERTEX_NORMAL; - const array *vertices = cached_data.vertices.data_for_time_no_check(time); + const array *vertices = + cached_data.vertices.data_for_time_no_check(time).get_data_or_null(); if (!vertices) { return; @@ -491,7 +494,8 @@ static void add_normals(const Int32ArraySamplePtr face_indices, *normals.getTimeSampling()); attr.std = ATTR_STD_VERTEX_NORMAL; - const array *vertices = cached_data.vertices.data_for_time_no_check(time); + const array *vertices = + cached_data.vertices.data_for_time_no_check(time).get_data_or_null(); if (!vertices) { return; @@ -1109,9 +1113,10 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER; attribute.type_desc = TypeFloat2; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); - const array *triangles_loops = cached_data.triangles_loops.data_for_time_no_check( - time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); + const array *triangles_loops = + cached_data.triangles_loops.data_for_time_no_check(time).get_data_or_null(); if (!triangles || !triangles_loops) { return; @@ -1164,7 +1169,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER_BYTE; attribute.type_desc = TypeRGBA; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); if (!triangles) { return; @@ -1220,7 +1226,8 @@ void AlembicObject::read_attribute(const ICompoundProperty &arb_geom_params, attribute.element = ATTR_ELEMENT_CORNER_BYTE; attribute.type_desc = TypeRGBA; - const array *triangles = cached_data.triangles.data_for_time_no_check(time); + const array *triangles = + cached_data.triangles.data_for_time_no_check(time).get_data_or_null(); if (!triangles) { return; @@ -1259,7 +1266,7 @@ static void update_attributes(AttributeSet &attributes, CachedData &cached_data, set cached_attributes; for (CachedData::CachedAttribute &attribute : cached_data.attributes) { - const array *attr_data = attribute.data.data_for_time(frame_time); + const array *attr_data = attribute.data.data_for_time(frame_time).get_data_or_null(); Attribute *attr = nullptr; if (attribute.std != ATTR_STD_NONE) { @@ -1558,7 +1565,7 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket()); - array *triangle_data = cached_data.triangles.data_for_time(frame_time); + array *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null(); if (triangle_data) { array triangles; array smooth; diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 6552336e6ab..0fc02f1da23 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -50,6 +50,78 @@ template struct is_array : public std::false_type { template struct is_array> : public std::true_type { }; +/* Holds the data for a cache lookup at a given time, as well as informations to + * help disambiguate successes or failures to get data from the cache. */ +template class CacheLookupResult { + enum class State { + NEW_DATA, + ALREADY_LOADED, + NO_DATA_FOR_TIME, + }; + + T *data; + State state; + + protected: + /* Prevent default construction outside of the class: for a valid result, we + * should use the static functions below. */ + CacheLookupResult() = default; + + public: + static CacheLookupResult new_data(T *data_) + { + CacheLookupResult result; + result.data = data_; + result.state = State::NEW_DATA; + return result; + } + + static CacheLookupResult no_data_found_for_time() + { + CacheLookupResult result; + result.data = nullptr; + result.state = State::NO_DATA_FOR_TIME; + return result; + } + + static CacheLookupResult already_loaded() + { + CacheLookupResult result; + result.data = nullptr; + result.state = State::ALREADY_LOADED; + return result; + } + + /* This should only be call if new data is available. */ + const T &get_data() const + { + assert(state == State::NEW_DATA); + assert(data != nullptr); + return *data; + } + + T *get_data_or_null() const + { + // data_ should already be null if there is no new data so no need to check + return data; + } + + bool has_new_data() const + { + return state == State::NEW_DATA; + } + + bool has_already_loaded() const + { + return state == State::ALREADY_LOADED; + } + + bool has_no_data_for_time() const + { + return state == State::NO_DATA_FOR_TIME; + } +}; + /* Store the data set for an animation at every time points, or at the beginning of the animation * for constant data. * @@ -79,10 +151,10 @@ template class DataStore { /* Get the data for the specified time. * Return nullptr if there is no data or if the data for this time was already loaded. */ - T *data_for_time(double time) + CacheLookupResult data_for_time(double time) { if (size() == 0) { - return nullptr; + return CacheLookupResult::no_data_found_for_time(); } std::pair index_pair; @@ -90,26 +162,26 @@ template class DataStore { DataTimePair &data_pair = data[index_pair.first]; if (last_loaded_time == data_pair.time) { - return nullptr; + return CacheLookupResult::already_loaded(); } last_loaded_time = data_pair.time; - return &data_pair.data; + return CacheLookupResult::new_data(&data_pair.data); } /* get the data for the specified time, but do not check if the data was already loaded for this * time return nullptr if there is no data */ - T *data_for_time_no_check(double time) + CacheLookupResult data_for_time_no_check(double time) { if (size() == 0) { - return nullptr; + return CacheLookupResult::no_data_found_for_time(); } std::pair index_pair; index_pair = time_sampling.getNearIndex(time, data.size()); DataTimePair &data_pair = data[index_pair.first]; - return &data_pair.data; + return CacheLookupResult::new_data(&data_pair.data); } void add_data(T &data_, double time) @@ -149,15 +221,15 @@ template class DataStore { * data for this time or it was already loaded, do nothing. */ void copy_to_socket(double time, Node *node, const SocketType *socket) { - T *data_ = data_for_time(time); + CacheLookupResult result = data_for_time(time); - if (data_ == nullptr) { + if (!result.has_new_data()) { return; } /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the * arrays to avoid reloading the data */ - T value = *data_; + T value = result.get_data(); node->set(*socket, value); } }; -- cgit v1.2.3