Skip to content

Commit d3801c4

Browse files
committed
Remove support for multi-pass I/O except PointDataLeafNode
Signed-off-by: Dan Bailey <danbailey@ilm.com>
1 parent c501029 commit d3801c4

3 files changed

Lines changed: 27 additions & 247 deletions

File tree

openvdb/openvdb/Grid.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,14 +1181,34 @@ struct TreeAdapter<tree::ValueAccessor<_TreeType> >
11811181
////////////////////////////////////////
11821182

11831183

1184+
namespace points {
1185+
1186+
template<typename T, Index Log2Dim> class PointDataLeafNode;
1187+
1188+
/// @brief Type trait that evaluates to true only for @c PointDataLeafNode instantiations.
1189+
template<typename T>
1190+
struct IsPointDataLeafNode : std::false_type {};
1191+
1192+
template<typename T, Index Log2Dim>
1193+
struct IsPointDataLeafNode<PointDataLeafNode<T, Log2Dim>> : std::true_type {};
1194+
1195+
} // namespace points
1196+
1197+
11841198
/// @brief Metafunction that specifies whether a given leaf node, tree, or grid type
1185-
/// requires multiple passes to read and write voxel data
1186-
/// @details Multi-pass I/O allows one to optimize the data layout of leaf nodes
1187-
/// for certain access patterns during delayed loading.
1188-
/// @sa io::MultiPass
1199+
/// requires multiple passes to read and write voxel data.
1200+
/// @details Multi-pass I/O allows leaf nodes to optimize their serialization layout
1201+
/// for delayed-load access patterns. Only @c PointDataLeafNode supports multi-pass I/O.
1202+
/// Defining a custom leaf node that inherits @c io::MultiPass is no longer permitted.
1203+
/// @sa points::IsPointDataLeafNode
11891204
template<typename LeafNodeType>
11901205
struct HasMultiPassIO {
1191-
static const bool value = std::is_base_of<io::MultiPass, LeafNodeType>::value;
1206+
static_assert(
1207+
!std::is_base_of<io::MultiPass, LeafNodeType>::value
1208+
|| points::IsPointDataLeafNode<LeafNodeType>::value,
1209+
"Only PointDataLeafNode may inherit from io::MultiPass; "
1210+
"use points::IsPointDataLeafNode to test for multi-pass I/O support.");
1211+
static const bool value = points::IsPointDataLeafNode<LeafNodeType>::value;
11921212
};
11931213

11941214
// Partial specialization for Tree types

openvdb/openvdb/io/io.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ std::ostream& operator<<(std::ostream&, const StreamMetadata::AuxDataMap&);
116116
////////////////////////////////////////
117117

118118

119-
/// @brief Leaf nodes that require multi-pass I/O must inherit from this struct.
120-
/// @sa Grid::hasMultiPassIO()
119+
/// @brief Tag for multi-pass I/O. Only points::PointDataLeafNode may inherit from this.
120+
/// @sa Grid::hasMultiPassIO(), points::IsPointDataLeafNode
121121
struct MultiPass {};
122122

123123

openvdb/openvdb/unittest/TestFile.cc

Lines changed: 0 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,246 +1522,6 @@ TEST_F(TestFile, testReadClippedGrid)
15221522
////////////////////////////////////////
15231523

15241524

1525-
namespace {
1526-
1527-
template<typename T, openvdb::Index Log2Dim> struct MultiPassLeafNode; // forward declaration
1528-
1529-
// Dummy value type
1530-
using MultiPassValue = openvdb::PointIndex<openvdb::Index32, 1000>;
1531-
1532-
// Tree configured to match the default OpenVDB configuration
1533-
using MultiPassTree = openvdb::tree::Tree<
1534-
openvdb::tree::RootNode<
1535-
openvdb::tree::InternalNode<
1536-
openvdb::tree::InternalNode<
1537-
MultiPassLeafNode<MultiPassValue, 3>, 4>, 5>>>;
1538-
1539-
using MultiPassGrid = openvdb::Grid<MultiPassTree>;
1540-
1541-
1542-
template<typename T, openvdb::Index Log2Dim>
1543-
struct MultiPassLeafNode: public openvdb::tree::LeafNode<T, Log2Dim>, openvdb::io::MultiPass
1544-
{
1545-
// The following had to be copied from the LeafNode class
1546-
// to make the derived class compatible with the tree structure.
1547-
1548-
using LeafNodeType = MultiPassLeafNode;
1549-
using Ptr = openvdb::SharedPtr<MultiPassLeafNode>;
1550-
using BaseLeaf = openvdb::tree::LeafNode<T, Log2Dim>;
1551-
using NodeMaskType = openvdb::util::NodeMask<Log2Dim>;
1552-
using ValueType = T;
1553-
using ValueOnCIter = typename BaseLeaf::template ValueIter<typename NodeMaskType::OnIterator,
1554-
const MultiPassLeafNode, const ValueType, typename BaseLeaf::ValueOn>;
1555-
using ChildOnIter = typename BaseLeaf::template ChildIter<typename NodeMaskType::OnIterator,
1556-
MultiPassLeafNode, typename BaseLeaf::ChildOn>;
1557-
using ChildOnCIter = typename BaseLeaf::template ChildIter<
1558-
typename NodeMaskType::OnIterator, const MultiPassLeafNode, typename BaseLeaf::ChildOn>;
1559-
1560-
MultiPassLeafNode(const openvdb::Coord& coords, const T& value, bool active = false)
1561-
: BaseLeaf(coords, value, active) {}
1562-
MultiPassLeafNode(openvdb::PartialCreate, const openvdb::Coord& coords, const T& value,
1563-
bool active = false): BaseLeaf(openvdb::PartialCreate(), coords, value, active) {}
1564-
MultiPassLeafNode(const MultiPassLeafNode& rhs): BaseLeaf(rhs) {}
1565-
1566-
ValueOnCIter cbeginValueOn() const { return ValueOnCIter(this->getValueMask().beginOn(),this); }
1567-
ChildOnCIter cbeginChildOn() const { return ChildOnCIter(this->getValueMask().endOn(), this); }
1568-
ChildOnIter beginChildOn() { return ChildOnIter(this->getValueMask().endOn(), this); }
1569-
1570-
// Methods in use for reading and writing multiple buffers
1571-
1572-
void readBuffers(std::istream& is, const openvdb::CoordBBox&, bool fromHalf = false)
1573-
{
1574-
this->readBuffers(is, fromHalf);
1575-
}
1576-
1577-
void readBuffers(std::istream& is, bool /*fromHalf*/ = false)
1578-
{
1579-
const openvdb::io::StreamMetadata::Ptr meta = openvdb::io::getStreamMetadataPtr(is);
1580-
if (!meta) {
1581-
OPENVDB_THROW(openvdb::IoError,
1582-
"Cannot write out a MultiBufferLeaf without StreamMetadata.");
1583-
}
1584-
1585-
// clamp pass to 16-bit integer
1586-
const uint32_t pass(static_cast<uint16_t>(meta->pass()));
1587-
1588-
// Read in the stored pass number.
1589-
uint32_t readPass;
1590-
is.read(reinterpret_cast<char*>(&readPass), sizeof(uint32_t));
1591-
EXPECT_EQ(pass, readPass);
1592-
// Record the pass number.
1593-
mReadPasses.push_back(readPass);
1594-
1595-
if (pass == 0) {
1596-
// Read in the node's origin.
1597-
openvdb::Coord origin;
1598-
is.read(reinterpret_cast<char*>(&origin), sizeof(openvdb::Coord));
1599-
EXPECT_EQ(origin, this->origin());
1600-
}
1601-
}
1602-
1603-
void writeBuffers(std::ostream& os, bool /*toHalf*/ = false) const
1604-
{
1605-
const openvdb::io::StreamMetadata::Ptr meta = openvdb::io::getStreamMetadataPtr(os);
1606-
if (!meta) {
1607-
OPENVDB_THROW(openvdb::IoError,
1608-
"Cannot read in a MultiBufferLeaf without StreamMetadata.");
1609-
}
1610-
1611-
// clamp pass to 16-bit integer
1612-
const uint32_t pass(static_cast<uint16_t>(meta->pass()));
1613-
1614-
// Leaf traversal analysis deduces the number of passes to perform for this leaf
1615-
// then updates the leaf traversal value to ensure all passes will be written.
1616-
if (meta->countingPasses()) {
1617-
if (mNumPasses > pass) meta->setPass(mNumPasses);
1618-
return;
1619-
}
1620-
1621-
// Record the pass number.
1622-
EXPECT_TRUE(mWritePassesPtr);
1623-
const_cast<std::vector<int>&>(*mWritePassesPtr).push_back(pass);
1624-
1625-
// Write out the pass number.
1626-
os.write(reinterpret_cast<const char*>(&pass), sizeof(uint32_t));
1627-
if (pass == 0) {
1628-
// Write out the node's origin and the pass number.
1629-
const auto origin = this->origin();
1630-
os.write(reinterpret_cast<const char*>(&origin), sizeof(openvdb::Coord));
1631-
}
1632-
}
1633-
1634-
1635-
uint32_t mNumPasses = 0;
1636-
// Pointer to external vector in which to record passes as they are written
1637-
std::vector<int>* mWritePassesPtr = nullptr;
1638-
// Vector in which to record passes as they are read
1639-
// (this needs to be internal, because leaf nodes are constructed as a grid is read)
1640-
std::vector<int> mReadPasses;
1641-
}; // struct MultiPassLeafNode
1642-
1643-
} // anonymous namespace
1644-
1645-
1646-
TEST_F(TestFile, testMultiPassIO)
1647-
{
1648-
using namespace openvdb;
1649-
1650-
openvdb::initialize();
1651-
MultiPassGrid::registerGrid();
1652-
1653-
// Create a multi-buffer grid.
1654-
const MultiPassGrid::Ptr grid = openvdb::createGrid<MultiPassGrid>();
1655-
grid->setName("test");
1656-
grid->setTransform(math::Transform::createLinearTransform(1.0));
1657-
MultiPassGrid::TreeType& tree = grid->tree();
1658-
tree.setValue(Coord(0, 0, 0), 5);
1659-
tree.setValue(Coord(0, 10, 0), 5);
1660-
EXPECT_EQ(2, int(tree.leafCount()));
1661-
1662-
const GridPtrVec grids{grid};
1663-
1664-
// Vector in which to record pass numbers (to ensure blocked ordering)
1665-
std::vector<int> writePasses;
1666-
{
1667-
// Specify the required number of I/O passes for each leaf node.
1668-
MultiPassGrid::TreeType::LeafIter leafIter = tree.beginLeaf();
1669-
leafIter->mNumPasses = 3;
1670-
leafIter->mWritePassesPtr = &writePasses;
1671-
++leafIter;
1672-
leafIter->mNumPasses = 2;
1673-
leafIter->mWritePassesPtr = &writePasses;
1674-
}
1675-
1676-
const char* filename = "testMultiPassIO.vdb";
1677-
SharedPtr<const char> scopedFile(filename, ::remove);
1678-
{
1679-
// Verify that passes are written to a file in the correct order.
1680-
io::File(filename).write(grids);
1681-
EXPECT_EQ(6, int(writePasses.size()));
1682-
EXPECT_EQ(0, writePasses[0]); // leaf 0
1683-
EXPECT_EQ(0, writePasses[1]); // leaf 1
1684-
EXPECT_EQ(1, writePasses[2]); // leaf 0
1685-
EXPECT_EQ(1, writePasses[3]); // leaf 1
1686-
EXPECT_EQ(2, writePasses[4]); // leaf 0
1687-
EXPECT_EQ(2, writePasses[5]); // leaf 1
1688-
}
1689-
{
1690-
// Verify that passes are read in the correct order.
1691-
io::File file(filename);
1692-
file.open();
1693-
const auto newGrid = GridBase::grid<MultiPassGrid>(file.readGrid("test"));
1694-
1695-
auto leafIter = newGrid->tree().beginLeaf();
1696-
EXPECT_EQ(3, int(leafIter->mReadPasses.size()));
1697-
EXPECT_EQ(0, leafIter->mReadPasses[0]);
1698-
EXPECT_EQ(1, leafIter->mReadPasses[1]);
1699-
EXPECT_EQ(2, leafIter->mReadPasses[2]);
1700-
++leafIter;
1701-
EXPECT_EQ(3, int(leafIter->mReadPasses.size()));
1702-
EXPECT_EQ(0, leafIter->mReadPasses[0]);
1703-
EXPECT_EQ(1, leafIter->mReadPasses[1]);
1704-
EXPECT_EQ(2, leafIter->mReadPasses[2]);
1705-
}
1706-
{
1707-
// Verify that when using multi-pass and bbox clipping that each leaf node
1708-
// is still being read before being clipped
1709-
io::File file(filename);
1710-
file.open();
1711-
const auto newGrid = GridBase::grid<MultiPassGrid>(
1712-
file.readGrid("test", BBoxd(Vec3d(0), Vec3d(1))));
1713-
EXPECT_EQ(Index64(1), newGrid->tree().leafCount());
1714-
1715-
auto leafIter = newGrid->tree().beginLeaf();
1716-
EXPECT_EQ(3, int(leafIter->mReadPasses.size()));
1717-
EXPECT_EQ(0, leafIter->mReadPasses[0]);
1718-
EXPECT_EQ(1, leafIter->mReadPasses[1]);
1719-
EXPECT_EQ(2, leafIter->mReadPasses[2]);
1720-
++leafIter;
1721-
EXPECT_TRUE(!leafIter); // second leaf node has now been clipped
1722-
}
1723-
1724-
// Clear the pass data.
1725-
writePasses.clear();
1726-
1727-
{
1728-
// Verify that passes are written to and read from a non-seekable stream
1729-
// in the correct order.
1730-
std::ostringstream ostr(std::ios_base::binary);
1731-
io::Stream(ostr).write(grids);
1732-
1733-
EXPECT_EQ(6, int(writePasses.size()));
1734-
EXPECT_EQ(0, writePasses[0]); // leaf 0
1735-
EXPECT_EQ(0, writePasses[1]); // leaf 1
1736-
EXPECT_EQ(1, writePasses[2]); // leaf 0
1737-
EXPECT_EQ(1, writePasses[3]); // leaf 1
1738-
EXPECT_EQ(2, writePasses[4]); // leaf 0
1739-
EXPECT_EQ(2, writePasses[5]); // leaf 1
1740-
1741-
std::istringstream is(ostr.str(), std::ios_base::binary);
1742-
io::Stream strm(is);
1743-
const auto streamedGrids = strm.getGrids();
1744-
EXPECT_EQ(1, int(streamedGrids->size()));
1745-
1746-
const auto newGrid = gridPtrCast<MultiPassGrid>(*streamedGrids->begin());
1747-
EXPECT_TRUE(bool(newGrid));
1748-
auto leafIter = newGrid->tree().beginLeaf();
1749-
EXPECT_EQ(3, int(leafIter->mReadPasses.size()));
1750-
EXPECT_EQ(0, leafIter->mReadPasses[0]);
1751-
EXPECT_EQ(1, leafIter->mReadPasses[1]);
1752-
EXPECT_EQ(2, leafIter->mReadPasses[2]);
1753-
++leafIter;
1754-
EXPECT_EQ(3, int(leafIter->mReadPasses.size()));
1755-
EXPECT_EQ(0, leafIter->mReadPasses[0]);
1756-
EXPECT_EQ(1, leafIter->mReadPasses[1]);
1757-
EXPECT_EQ(2, leafIter->mReadPasses[2]);
1758-
}
1759-
}
1760-
1761-
1762-
////////////////////////////////////////
1763-
1764-
17651525
TEST_F(TestFile, testHasGrid)
17661526
{
17671527
using namespace openvdb;

0 commit comments

Comments
 (0)