Problem
nanovdb::tools::VoxelBlockManagerHandle<BufferT>'s eight pointer accessors static_cast directly from the buffer's data() / deviceData():
// nanovdb/tools/VoxelBlockManager.h:152 (and 159, 166, 173, 185, 188, 191, 194)
deviceFirstLeafID() { return static_cast<uint32_t*>(mFirstLeafID.deviceData()); }
This compiles when deviceData() returns void* (as NanoVDB's own HostBuffer / DeviceBuffer / UnifiedBuffer do), but a static_cast from any typed pointer to uint32_t* is ill-formed. A custom BufferT whose data() / deviceData() return e.g. uint8_t* fails to compile as soon as one of these accessors is instantiated:
nanovdb/tools/VoxelBlockManager.h(152): error: invalid type conversion
deviceFirstLeafID() { return static_cast<uint32_t*>(mFirstLeafID.deviceData()); }
detected during instantiation of ... VoxelBlockManagerHandle<BufferT>::deviceFirstLeafID()
[with BufferT=fvdb::TorchDeviceBuffer, U=fvdb::TorchDeviceBuffer]
Nothing in the BufferTraits contract requires void* returns — and the rest of the generic surface (GridHandle, cuda::mergeGridHandles, buildVoxelBlockManager's BufferT::create path, etc.) works fine with typed-pointer buffers because a typed pointer converts implicitly to void*. VoxelBlockManagerHandle is the outlier: it's the only place that needs the conversion in the other direction and spells it as a single static_cast.
Where this bites
fvdb-core's TorchDeviceBuffer (its BufferT backed by PyTorch's caching allocator, uint8_t* data()/deviceData()) is used as the buffer type for grid handles throughout fvdb. Building a VoxelBlockManagerHandle<TorchDeviceBuffer> — the natural way to keep the VBM's firstLeafID / jumpMap arrays in the same memory pool as everything else, per the #2232 direction — fails to compile. fvdb currently works around it by allocating the arrays itself and launching BuildVoxelBlockManagerFunctor directly, bypassing the handle (openvdb/fvdb-core#733).
Proposed fix
Route the casts through void*, which is valid for both void* and typed-pointer buffers and is a no-op for the existing types:
deviceFirstLeafID() { return static_cast<uint32_t*>(static_cast<void*>(mFirstLeafID.deviceData())); }
(equivalently on the const overloads via const void*), applied to all eight accessors: hostFirstLeafID ×2, hostJumpMap ×2, deviceFirstLeafID ×2, deviceJumpMap ×2.
A TestNanoVDB-side guard could instantiate the handle over a minimal buffer whose data()/deviceData() return uint8_t* to keep this from regressing.
Happy to put up the one-file PR. Related context: the injectable-memory-resource roadmap #2232, where downstream buffer/resource types are expected to plug into these generic seams.
Problem
nanovdb::tools::VoxelBlockManagerHandle<BufferT>'s eight pointer accessorsstatic_castdirectly from the buffer'sdata()/deviceData():This compiles when
deviceData()returnsvoid*(as NanoVDB's ownHostBuffer/DeviceBuffer/UnifiedBufferdo), but astatic_castfrom any typed pointer touint32_t*is ill-formed. A customBufferTwhosedata()/deviceData()return e.g.uint8_t*fails to compile as soon as one of these accessors is instantiated:Nothing in the
BufferTraitscontract requiresvoid*returns — and the rest of the generic surface (GridHandle,cuda::mergeGridHandles,buildVoxelBlockManager'sBufferT::createpath, etc.) works fine with typed-pointer buffers because a typed pointer converts implicitly tovoid*.VoxelBlockManagerHandleis the outlier: it's the only place that needs the conversion in the other direction and spells it as a singlestatic_cast.Where this bites
fvdb-core's
TorchDeviceBuffer(itsBufferTbacked by PyTorch's caching allocator,uint8_t* data()/deviceData()) is used as the buffer type for grid handles throughout fvdb. Building aVoxelBlockManagerHandle<TorchDeviceBuffer>— the natural way to keep the VBM'sfirstLeafID/jumpMaparrays in the same memory pool as everything else, per the #2232 direction — fails to compile. fvdb currently works around it by allocating the arrays itself and launchingBuildVoxelBlockManagerFunctordirectly, bypassing the handle (openvdb/fvdb-core#733).Proposed fix
Route the casts through
void*, which is valid for bothvoid*and typed-pointer buffers and is a no-op for the existing types:(equivalently on the const overloads via
const void*), applied to all eight accessors:hostFirstLeafID×2,hostJumpMap×2,deviceFirstLeafID×2,deviceJumpMap×2.A
TestNanoVDB-side guard could instantiate the handle over a minimal buffer whosedata()/deviceData()returnuint8_t*to keep this from regressing.Happy to put up the one-file PR. Related context: the injectable-memory-resource roadmap #2232, where downstream buffer/resource types are expected to plug into these generic seams.