14# include <openvdb/Grid.h>
15# include <openvdb/tools/Prune.h>
22VolumeGridData::VolumeGridData()
24 tree_access_token_ = std::make_shared<AccessToken>(*
this);
28 template<
typename Gr
idT> openvdb::GridBase::Ptr
operator()()
const
30 return GridT::create();
34static openvdb::GridBase::Ptr create_grid_for_type(
const VolumeGridType grid_type)
36 return BKE_volume_grid_type_operation(grid_type, CreateGridOp{});
40 : VolumeGridData(create_grid_for_type(grid_type))
44VolumeGridData::VolumeGridData(std::shared_ptr<openvdb::GridBase> grid)
45 : grid_(std::move(grid)), tree_loaded_(
true), transform_loaded_(
true), meta_data_loaded_(
true)
51 tree_sharing_info_ = OpenvdbTreeSharingInfo::make(grid_->baseTreePtr());
52 tree_access_token_ = std::make_shared<AccessToken>(*
this);
55VolumeGridData::VolumeGridData(std::function<LazyLoadedGrid()> lazy_load_grid,
56 std::shared_ptr<openvdb::GridBase> meta_data_and_transform_grid)
57 : grid_(std::move(meta_data_and_transform_grid)), lazy_load_grid_(std::move(lazy_load_grid))
60 transform_loaded_ =
true;
61 meta_data_loaded_ =
true;
63 tree_access_token_ = std::make_shared<AccessToken>(*
this);
66VolumeGridData::~VolumeGridData() =
default;
68void VolumeGridData::delete_self()
73const openvdb::GridBase &VolumeGridData::grid(VolumeTreeAccessToken &r_token)
const
75 return *this->grid_ptr(r_token);
78openvdb::GridBase &VolumeGridData::grid_for_write(VolumeTreeAccessToken &r_token)
80 return *this->grid_ptr_for_write(r_token);
83std::shared_ptr<const openvdb::GridBase> VolumeGridData::grid_ptr(
84 VolumeTreeAccessToken &r_token)
const
86 std::lock_guard
lock{mutex_};
87 this->ensure_grid_loaded();
88 r_token.token_ = tree_access_token_;
92std::shared_ptr<openvdb::GridBase> VolumeGridData::grid_ptr_for_write(
93 VolumeTreeAccessToken &r_token)
96 std::lock_guard
lock{mutex_};
97 this->ensure_grid_loaded();
98 r_token.token_ = tree_access_token_;
99 if (tree_sharing_info_->is_mutable()) {
100 tree_sharing_info_->tag_ensured_mutable();
103 auto tree_copy = grid_->baseTree().copy();
104 grid_->setTree(tree_copy);
105 tree_sharing_info_ = OpenvdbTreeSharingInfo::make(std::move(tree_copy));
108 lazy_load_grid_ = {};
112const openvdb::math::Transform &VolumeGridData::transform()
const
114 std::lock_guard
lock{mutex_};
115 if (!transform_loaded_) {
116 this->ensure_grid_loaded();
118 return grid_->transform();
121openvdb::math::Transform &VolumeGridData::transform_for_write()
124 std::lock_guard
lock{mutex_};
125 if (!transform_loaded_) {
126 this->ensure_grid_loaded();
128 return grid_->transform();
131std::string VolumeGridData::name()
const
133 std::lock_guard
lock{mutex_};
134 if (!meta_data_loaded_) {
135 this->ensure_grid_loaded();
137 return grid_->getName();
143 std::lock_guard
lock{mutex_};
144 if (!meta_data_loaded_) {
145 this->ensure_grid_loaded();
147 grid_->setName(
name);
152 std::lock_guard
lock{mutex_};
153 if (!meta_data_loaded_) {
154 this->ensure_grid_loaded();
159std::optional<VolumeGridType> VolumeGridData::grid_type_without_load()
const
161 std::lock_guard
lock{mutex_};
162 if (!meta_data_loaded_) {
168openvdb::GridClass VolumeGridData::grid_class()
const
170 std::lock_guard
lock{mutex_};
171 if (!meta_data_loaded_) {
172 this->ensure_grid_loaded();
174 return grid_->getGridClass();
177bool VolumeGridData::is_reloadable()
const
179 return bool(lazy_load_grid_);
182void VolumeGridData::tag_tree_modified()
const
184 active_voxels_mutex_.tag_dirty();
185 active_leaf_voxels_mutex_.tag_dirty();
186 active_tiles_mutex_.tag_dirty();
187 size_in_bytes_mutex_.tag_dirty();
188 active_bounds_mutex_.tag_dirty();
191bool VolumeGridData::is_loaded()
const
193 std::lock_guard
lock{mutex_};
194 return tree_loaded_ && transform_loaded_ && meta_data_loaded_;
197void VolumeGridData::count_memory(MemoryCounter &memory)
const
199 std::lock_guard
lock{mutex_};
203 memory.add_shared(tree_sharing_info_.get(), [&](MemoryCounter &shared_memory) {
204 shared_memory.add(this->size_in_bytes());
208int64_t VolumeGridData::active_voxels()
const
210 active_voxels_mutex_.ensure([&]() {
211 VolumeTreeAccessToken token;
212 const openvdb::GridBase &grid = this->grid(token);
213 const openvdb::TreeBase &
tree = grid.baseTree();
214 active_voxels_ =
tree.activeVoxelCount();
216 return active_voxels_;
219int64_t VolumeGridData::active_leaf_voxels()
const
221 active_leaf_voxels_mutex_.ensure([&]() {
222 VolumeTreeAccessToken token;
223 const openvdb::GridBase &grid = this->grid(token);
224 const openvdb::TreeBase &
tree = grid.baseTree();
225 active_leaf_voxels_ =
tree.activeLeafVoxelCount();
227 return active_leaf_voxels_;
230int64_t VolumeGridData::active_tiles()
const
232 active_tiles_mutex_.ensure([&]() {
233 VolumeTreeAccessToken token;
234 const openvdb::GridBase &grid = this->grid(token);
235 const openvdb::TreeBase &
tree = grid.baseTree();
236 active_tiles_ =
tree.activeTileCount();
238 return active_tiles_;
241int64_t VolumeGridData::size_in_bytes()
const
243 size_in_bytes_mutex_.ensure([&]() {
244 VolumeTreeAccessToken token;
245 const openvdb::GridBase &grid = this->grid(token);
246 const openvdb::TreeBase &
tree = grid.baseTree();
247 size_in_bytes_ =
tree.memUsage();
249 return size_in_bytes_;
252const openvdb::CoordBBox &VolumeGridData::active_bounds()
const
254 active_bounds_mutex_.ensure([&]() {
255 VolumeTreeAccessToken token;
256 const openvdb::GridBase &grid = this->grid(token);
257 const openvdb::TreeBase &
tree = grid.baseTree();
258 tree.evalActiveVoxelBoundingBox(active_bounds_);
260 return active_bounds_;
263std::string VolumeGridData::error_message()
const
265 std::lock_guard
lock{mutex_};
266 return error_message_;
269void VolumeGridData::unload_tree_if_possible()
const
271 std::lock_guard
lock{mutex_};
278 if (!this->is_reloadable()) {
281 if (tree_access_token_.use_count() != 1) {
286 tree_loaded_ =
false;
287 tree_sharing_info_.reset();
290GVolumeGrid VolumeGridData::copy()
const
292 std::lock_guard
lock{mutex_};
293 this->ensure_grid_loaded();
295 VolumeGridData *new_copy =
new (
MEM_mallocN(
sizeof(VolumeGridData), __func__)) VolumeGridData();
297 new_copy->grid_ = grid_->copyGrid();
298 new_copy->tree_sharing_info_ = tree_sharing_info_;
299 new_copy->tree_loaded_ = tree_loaded_;
300 new_copy->transform_loaded_ = transform_loaded_;
301 new_copy->meta_data_loaded_ = meta_data_loaded_;
302 return GVolumeGrid(new_copy);
305void VolumeGridData::ensure_grid_loaded()
const
310 if (tree_loaded_ && transform_loaded_ && meta_data_loaded_) {
314 LazyLoadedGrid loaded_grid;
316 threading::isolate_task([&]() {
317 error_message_.clear();
319 loaded_grid = lazy_load_grid_();
321 catch (
const openvdb::IoError &
e) {
322 error_message_ =
e.what();
325 error_message_ =
"Unknown error reading VDB file";
328 if (!loaded_grid.grid) {
331 const openvdb::Name &grid_type = grid_->type();
332 if (openvdb::GridBase::isRegistered(grid_type)) {
334 loaded_grid.grid = openvdb::GridBase::createGrid(grid_type);
338 if (!loaded_grid.grid) {
340 loaded_grid.grid = openvdb::FloatGrid::create();
343 BLI_assert(loaded_grid.grid.use_count() == 1);
345 if (!loaded_grid.tree_sharing_info) {
347 loaded_grid.tree_sharing_info = OpenvdbTreeSharingInfo::make(loaded_grid.grid->baseTreePtr());
354 grid_->setTree(loaded_grid.grid->baseTreePtr());
355 if (!transform_loaded_) {
356 grid_->setTransform(loaded_grid.grid->transformPtr());
360 grid_ = std::move(loaded_grid.grid);
365 tree_sharing_info_ = std::move(loaded_grid.tree_sharing_info);
368 transform_loaded_ =
true;
369 meta_data_loaded_ =
true;
372GVolumeGrid::GVolumeGrid(std::shared_ptr<openvdb::GridBase> grid)
374 data_ = ImplicitSharingPtr(MEM_new<VolumeGridData>(__func__, std::move(grid)));
378 : GVolumeGrid(create_grid_for_type(grid_type))
382VolumeGridData &GVolumeGrid::get_for_write()
385 if (data_->is_mutable()) {
386 data_->tag_ensured_mutable();
389 *
this = data_->copy();
391 return const_cast<VolumeGridData &
>(*data_);
396 if (
tree.isType<openvdb::FloatTree>()) {
399 if (
tree.isType<openvdb::Vec3fTree>()) {
402 if (
tree.isType<openvdb::BoolTree>()) {
405 if (
tree.isType<openvdb::DoubleTree>()) {
408 if (
tree.isType<openvdb::Int32Tree>()) {
411 if (
tree.isType<openvdb::Int64Tree>()) {
414 if (
tree.isType<openvdb::Vec3ITree>()) {
417 if (
tree.isType<openvdb::Vec3dTree>()) {
420 if (
tree.isType<openvdb::MaskTree>()) {
423 if (
tree.isType<openvdb::points::PointDataTree>()) {
434ImplicitSharingPtr<> OpenvdbTreeSharingInfo::make(std::shared_ptr<openvdb::tree::TreeBase>
tree)
436 return ImplicitSharingPtr<>{MEM_new<OpenvdbTreeSharingInfo>(__func__, std::move(
tree))};
439OpenvdbTreeSharingInfo::OpenvdbTreeSharingInfo(std::shared_ptr<openvdb::tree::TreeBase>
tree)
440 : tree_(std::move(
tree))
444void OpenvdbTreeSharingInfo::delete_self_with_data()
449void OpenvdbTreeSharingInfo::delete_data_only()
454VolumeTreeAccessToken::~VolumeTreeAccessToken()
456 const VolumeGridData *grid = token_ ? &token_->grid :
nullptr;
461 grid->unload_tree_if_possible();
480 return grid.grid_type();
511 return BKE_volume_transform_to_blender(grid.transform());
521 grid.transform_for_write() = BKE_volume_transform_to_openvdb(matrix);
530 VolumeTreeAccessToken tree_token;
531 grid.grid_for_write(tree_token).clear();
532 grid.tag_tree_modified();
541 return grid.is_loaded();
551 grid.count_memory(memory);
557void load(
const VolumeGridData &grid)
560 VolumeTreeAccessToken tree_token;
562 grid.grid(tree_token);
571 return grid.error_message();
584template<
typename LeafNodeT>
585static void parallel_grid_topology_tasks_leaf_node(
const LeafNodeT &node,
586 const ProcessLeafFn process_leaf_fn,
589 using NodeMaskT =
typename LeafNodeT::NodeMaskType;
591 const int on_count = node.onVoxelCount();
595 const int on_count_threshold = 64;
596 if (on_count <= on_count_threshold) {
599 for (
auto value_iter = node.cbeginValueOn(); value_iter.test(); ++value_iter) {
600 const openvdb::Coord coord = value_iter.getCoord();
608 const NodeMaskT &value_mask = node.getValueMask();
609 const openvdb::CoordBBox bbox = node.getNodeBoundingBox();
611 for (
auto value_iter = node.cbeginValueOn(); value_iter.test(); ++value_iter) {
612 r_voxels[value_iter.pos()] = value_iter.getCoord();
620template<
typename InternalNodeT>
621static void parallel_grid_topology_tasks_internal_node(
const InternalNodeT &node,
622 const ProcessLeafFn process_leaf_fn,
623 const ProcessVoxelsFn process_voxels_fn,
624 const ProcessTilesFn process_tiles_fn)
626 using ChildNodeT =
typename InternalNodeT::ChildNodeType;
627 using LeafNodeT =
typename InternalNodeT::LeafNodeType;
628 using NodeMaskT =
typename InternalNodeT::NodeMaskType;
629 using UnionT =
typename InternalNodeT::UnionType;
632 const NodeMaskT &child_mask = node.getChildMask();
633 const UnionT *table = node.getTable();
635 for (
auto child_mask_iter = child_mask.beginOn(); child_mask_iter.test(); ++child_mask_iter) {
636 child_indices.
append(child_mask_iter.pos());
643 Vector<openvdb::Coord, 1024> gathered_voxels;
644 for (const int child_index : child_indices.as_span().slice(range)) {
645 const ChildNodeT &child = *table[child_index].getChild();
646 if constexpr (std::is_same_v<ChildNodeT, LeafNodeT>) {
647 parallel_grid_topology_tasks_leaf_node(child, process_leaf_fn, gathered_voxels);
649 if (gathered_voxels.size() >= 512) {
650 process_voxels_fn(gathered_voxels);
651 gathered_voxels.clear();
656 parallel_grid_topology_tasks_internal_node(
657 child, process_leaf_fn, process_voxels_fn, process_tiles_fn);
661 if (!gathered_voxels.is_empty()) {
662 process_voxels_fn(gathered_voxels);
663 gathered_voxels.clear();
670 const NodeMaskT &value_mask = node.getValueMask();
672 for (
auto value_mask_iter = value_mask.beginOn(); value_mask_iter.test(); ++value_mask_iter) {
673 const openvdb::Index32 index = value_mask_iter.pos();
674 const openvdb::Coord tile_origin = node.offsetToGlobalCoord(index);
675 const openvdb::CoordBBox tile_bbox = openvdb::CoordBBox::createCube(tile_origin,
677 tile_bboxes.
append(tile_bbox);
680 process_tiles_fn(tile_bboxes);
685void parallel_grid_topology_tasks(
const openvdb::MaskTree &mask_tree,
686 const ProcessLeafFn process_leaf_fn,
687 const ProcessVoxelsFn process_voxels_fn,
688 const ProcessTilesFn process_tiles_fn)
691 for (
auto root_child_iter = mask_tree.cbeginRootChildren(); root_child_iter.test();
694 const auto &internal_node = *root_child_iter;
695 parallel_grid_topology_tasks_internal_node(
696 internal_node, process_leaf_fn, process_voxels_fn, process_tiles_fn);
700openvdb::GridBase::Ptr create_grid_with_topology(
const openvdb::MaskTree &topology,
701 const openvdb::math::Transform &
transform,
704 openvdb::GridBase::Ptr grid;
705 BKE_volume_grid_type_to_static_type(grid_type, [&](
auto type_tag) {
706 using GridT =
typename decltype(type_tag)::type;
707 using TreeT =
typename GridT::TreeType;
708 using ValueType =
typename TreeT::ValueType;
709 const ValueType background{};
710 auto tree = std::make_shared<TreeT>(topology, background, openvdb::TopologyCopy());
711 grid = openvdb::createGrid(std::move(
tree));
717void set_grid_values(openvdb::GridBase &grid_base,
722 to_typed_grid(grid_base, [&](
auto &grid) {
723 using GridT = std::decay_t<
decltype(grid)>;
724 using ValueType =
typename GridT::ValueType;
725 const ValueType *
data =
static_cast<const ValueType *
>(values.data());
727 auto accessor = grid.getUnsafeAccessor();
729 accessor.setValue(voxels[
i],
data[
i]);
734void set_tile_values(openvdb::GridBase &grid_base,
739 to_typed_grid(grid_base, [&](
auto &grid) {
740 using GridT =
typename std::decay_t<
decltype(grid)>;
741 using TreeT =
typename GridT::TreeType;
742 using ValueType =
typename GridT::ValueType;
743 auto &
tree = grid.tree();
745 const ValueType *computed_values =
static_cast<const ValueType *
>(values.data());
747 const auto set_tile_value = [&](
auto &node,
const openvdb::Coord &coord_in_tile,
auto value) {
748 const openvdb::Index n = node.coordToOffset(coord_in_tile);
754 using UnionType =
typename std::decay_t<
decltype(node)>::UnionType;
755 auto *table =
const_cast<UnionType *
>(node.getTable());
756 table[n].setValue(value);
759 for (
const int i :
tiles.index_range()) {
761 const openvdb::Coord coord_in_tile =
tile.min();
762 const auto &computed_value = computed_values[
i];
763 using InternalNode1 =
typename TreeT::RootNodeType::ChildNodeType;
764 using InternalNode2 =
typename InternalNode1::ChildNodeType;
766 if (
auto *node =
tree.template probeNode<InternalNode2>(coord_in_tile)) {
767 set_tile_value(*node, coord_in_tile, computed_value);
769 else if (
auto *node =
tree.template probeNode<InternalNode1>(coord_in_tile)) {
770 set_tile_value(*node, coord_in_tile, computed_value);
779void set_mask_leaf_buffer_from_bools(openvdb::BoolGrid &grid,
784 auto accessor = grid.getUnsafeAccessor();
787 const openvdb::Coord &coord = voxels[
i];
788 accessor.setValue(coord, values[
i]);
792void set_grid_background(openvdb::GridBase &grid_base,
const GPointer value)
794 to_typed_grid(grid_base, [&](
auto &grid) {
795 using GridT = std::decay_t<
decltype(grid)>;
796 using ValueType =
typename GridT::ValueType;
797 auto &
tree = grid.tree();
799 BLI_assert(value.type()->size ==
sizeof(ValueType));
800 tree.root().setBackground(*
static_cast<const ValueType *
>(value.get()),
true);
804void prune_inactive(openvdb::GridBase &grid_base)
806 to_typed_grid(grid_base, [&](
auto &grid) { openvdb::tools::pruneInactive(grid.tree()); });
@ VOLUME_GRID_VECTOR_FLOAT
@ VOLUME_GRID_VECTOR_DOUBLE
#define BLI_assert_unreachable()
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
void foreach_index_optimized(Fn &&fn) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
IndexRange index_range() const
void append(const T &value)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
const ccl_global KernelWorkTile * tile
void * MEM_mallocN(size_t len, const char *str)
float4x4 get_transform_matrix(const VolumeGridData &grid)
std::string get_name(const VolumeGridData &grid)
void count_memory(const VolumeGridData &grid, MemoryCounter &memory)
int get_channels_num(VolumeGridType type)
std::string error_message_from_load(const VolumeGridData &grid)
void load(const VolumeGridData &grid)
void clear_tree(VolumeGridData &grid)
VolumeGridType get_type(const VolumeGridData &grid)
void set_transform_matrix(VolumeGridData &grid, const float4x4 &matrix)
bool is_loaded(const VolumeGridData &grid)
MatBase< float, 4, 4 > float4x4
static MatBase identity()