commit a51afffd2f45d3aede0aed68744a6016cee5931b Author: Brecht Van Lommel Date: Thu Mar 12 17:47:14 2020 +0100 Cycles: WIP sparse 3D texture support (CPU only) diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 57e8523e02a..73330460238 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -501,8 +501,12 @@ class CPUDevice : public Device { texture_info.resize(slot + 128); } - texture_info[slot] = mem.info; - texture_info[slot].data = (uint64_t)mem.host_pointer; + TextureInfo &info = texture_info[slot]; + + info = mem.info; + info.data = (uint64_t)mem.host_pointer; + info.sparse_tile_map = (mem.sparse_tile_map) ? (uint64_t)mem.sparse_tile_map->host_pointer : 0; + need_texture_info = true; } diff --git a/intern/cycles/device/device_memory.cpp b/intern/cycles/device/device_memory.cpp index 36a0247bb3d..177486ba966 100644 --- a/intern/cycles/device/device_memory.cpp +++ b/intern/cycles/device/device_memory.cpp @@ -145,7 +145,7 @@ device_texture::device_texture(Device *device, ImageDataType image_data_type, InterpolationType interpolation, ExtensionType extension) - : device_memory(device, name, MEM_TEXTURE), slot(slot) + : device_memory(device, name, MEM_TEXTURE), slot(slot), sparse_tile_map(NULL) { switch (image_data_type) { case IMAGE_DATA_TYPE_FLOAT4: @@ -193,6 +193,10 @@ device_texture::device_texture(Device *device, device_texture::~device_texture() { + device_free(); + host_free(); + + delete sparse_tile_map; } /* Host memory allocation. */ @@ -219,8 +223,22 @@ void *device_texture::alloc(const size_t width, const size_t height, const size_ return host_pointer; } +void device_texture::alloc_sparse_tile_map(const vector &tile_map) +{ + delete sparse_tile_map; + + sparse_tile_name = std::string(name) + "_tile_map"; + sparse_tile_map = new device_vector(device, sparse_tile_name.c_str(), MEM_READ_ONLY); + sparse_tile_map->alloc(tile_map.size()); + memcpy(sparse_tile_map->data(), tile_map.data(), sizeof(uint) * tile_map.size()); +} + void device_texture::copy_to_device() { + if (sparse_tile_map) { + sparse_tile_map->copy_to_device(); + } + device_copy_to(); } diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 1c20db900bc..eae5f930da5 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -524,11 +524,15 @@ class device_texture : public device_memory { ~device_texture(); void *alloc(const size_t width, const size_t height, const size_t depth = 0); + void alloc_sparse_tile_map(const vector &tile_map); void copy_to_device(); uint slot; TextureInfo info; + string sparse_tile_name; + device_vector *sparse_tile_map; + protected: size_t size(const size_t width, const size_t height, const size_t depth) { diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index f87501db258..3b04b647aa3 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN * instruction sets. */ namespace { -template struct TextureInterpolator { +template struct TextureInterpolator { #define SET_CUBIC_SPLINE_WEIGHTS(u, t) \ { \ u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \ @@ -88,6 +88,37 @@ template struct TextureInterpolator { return read(data[y * width + x]); } + static ccl_always_inline float4 read(const TextureInfo &info, + const T *data, + int x, + int y, + int z, + const int width, + const int height, + const int depth) + { + if (sparse) { + uint tile = texture_sparse_tile_index_3d(width, height, depth, x, y, z); + if (tile == TEXTURE_SPARSE_TILE_NONE) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + + tile = ((uint *)info.sparse_tile_map)[tile]; + if (tile == TEXTURE_SPARSE_TILE_NONE) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + + tile *= TEXTURE_SPARSE_TILE_SIZE_3D; + return read(data[tile + texture_sparse_voxel_index_3d(x, y, z)]); + } + else { + if (x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= depth) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + return read(data[x + y * width + z * width * height]); + } + } + static ccl_always_inline int wrap_periodic(int x, int width) { x %= width; @@ -267,29 +298,8 @@ template struct TextureInterpolator { frac(y * (float)height, &iy); frac(z * (float)depth, &iz); - switch (info.extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); - break; - case EXTENSION_CLIP: - if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - ATTR_FALLTHROUGH; - case EXTENSION_EXTEND: - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - const T *data = (const T *)info.data; - return read(data[ix + iy * width + iz * width * height]); + return read(info, data, ix, iy, iz, width, height, depth); } static ccl_always_inline float4 interp_3d_linear(const TextureInfo &info, @@ -301,54 +311,24 @@ template struct TextureInterpolator { int height = info.height; int depth = info.depth; int ix, iy, iz; - int nix, niy, niz; float tx = frac(x * (float)width - 0.5f, &ix); float ty = frac(y * (float)height - 0.5f, &iy); float tz = frac(z * (float)depth - 0.5f, &iz); - switch (info.extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); - - nix = wrap_periodic(ix + 1, width); - niy = wrap_periodic(iy + 1, height); - niz = wrap_periodic(iz + 1, depth); - break; - case EXTENSION_CLIP: - if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - ATTR_FALLTHROUGH; - case EXTENSION_EXTEND: - nix = wrap_clamp(ix + 1, width); - niy = wrap_clamp(iy + 1, height); - niz = wrap_clamp(iz + 1, depth); - - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - const T *data = (const T *)info.data; float4 r; r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * - read(data[ix + iy * width + iz * width * height]); - r += (1.0f - tz) * (1.0f - ty) * tx * read(data[nix + iy * width + iz * width * height]); - r += (1.0f - tz) * ty * (1.0f - tx) * read(data[ix + niy * width + iz * width * height]); - r += (1.0f - tz) * ty * tx * read(data[nix + niy * width + iz * width * height]); + read(info, data, ix, iy, iz, width, height, depth); + r += (1.0f - tz) * (1.0f - ty) * tx * read(info, data, ix + 1, iy, iz, width, height, depth); + r += (1.0f - tz) * ty * (1.0f - tx) * read(info, data, ix, iy + 1, iz, width, height, depth); + r += (1.0f - tz) * ty * tx * read(info, data, ix + 1, iy + 1, iz, width, height, depth); - r += tz * (1.0f - ty) * (1.0f - tx) * read(data[ix + iy * width + niz * width * height]); - r += tz * (1.0f - ty) * tx * read(data[nix + iy * width + niz * width * height]); - r += tz * ty * (1.0f - tx) * read(data[ix + niy * width + niz * width * height]); - r += tz * ty * tx * read(data[nix + niy * width + niz * width * height]); + r += tz * (1.0f - ty) * (1.0f - tx) * read(info, data, ix, iy, iz + 1, width, height, depth); + r += tz * (1.0f - ty) * tx * read(info, data, ix + 1, iy, iz + 1, width, height, depth); + r += tz * ty * (1.0f - tx) * read(info, data, ix, iy + 1, iz + 1, width, height, depth); + r += tz * ty * tx * read(info, data, ix + 1, iy + 1, iz + 1, width, height, depth); return r; } @@ -371,68 +351,20 @@ template struct TextureInterpolator { int height = info.height; int depth = info.depth; int ix, iy, iz; - int nix, niy, niz; /* Tricubic b-spline interpolation. */ const float tx = frac(x * (float)width - 0.5f, &ix); const float ty = frac(y * (float)height - 0.5f, &iy); const float tz = frac(z * (float)depth - 0.5f, &iz); - int pix, piy, piz, nnix, nniy, nniz; - - switch (info.extension) { - case EXTENSION_REPEAT: - ix = wrap_periodic(ix, width); - iy = wrap_periodic(iy, height); - iz = wrap_periodic(iz, depth); - - pix = wrap_periodic(ix - 1, width); - piy = wrap_periodic(iy - 1, height); - piz = wrap_periodic(iz - 1, depth); - - nix = wrap_periodic(ix + 1, width); - niy = wrap_periodic(iy + 1, height); - niz = wrap_periodic(iz + 1, depth); - - nnix = wrap_periodic(ix + 2, width); - nniy = wrap_periodic(iy + 2, height); - nniz = wrap_periodic(iz + 2, depth); - break; - case EXTENSION_CLIP: - if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - ATTR_FALLTHROUGH; - case EXTENSION_EXTEND: - pix = wrap_clamp(ix - 1, width); - piy = wrap_clamp(iy - 1, height); - piz = wrap_clamp(iz - 1, depth); - - nix = wrap_clamp(ix + 1, width); - niy = wrap_clamp(iy + 1, height); - niz = wrap_clamp(iz + 1, depth); - - nnix = wrap_clamp(ix + 2, width); - nniy = wrap_clamp(iy + 2, height); - nniz = wrap_clamp(iz + 2, depth); - - ix = wrap_clamp(ix, width); - iy = wrap_clamp(iy, height); - iz = wrap_clamp(iz, depth); - break; - default: - kernel_assert(0); - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - const int xc[4] = {pix, ix, nix, nnix}; - const int yc[4] = {width * piy, width * iy, width * niy, width * nniy}; - const int zc[4] = { - width * height * piz, width * height * iz, width * height * niz, width * height * nniz}; + const int xc[4] = {ix - 1, ix, ix + 1, ix + 2}; + const int yc[4] = {iy - 1, iy, iy + 1, iy + 2}; + const int zc[4] = {iz - 1, iz, iz + 1, iz + 2}; float u[4], v[4], w[4]; /* Some helper macro to keep code reasonable size, * let compiler to inline all the matrix multiplications. */ -#define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]])) +#define DATA(x, y, z) (read(info, data, xc[x], yc[y], zc[z], width, height, depth)) #define COL_TERM(col, row) \ (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \ u[3] * DATA(3, col, row))) @@ -476,21 +408,21 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, fl switch (info.data_type) { case IMAGE_DATA_TYPE_HALF: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_BYTE: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_USHORT: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_FLOAT: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_HALF4: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_BYTE4: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_USHORT4: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); case IMAGE_DATA_TYPE_FLOAT4: - return TextureInterpolator::interp(info, x, y); + return TextureInterpolator::interp(info, x, y); default: assert(0); return make_float4( @@ -509,28 +441,53 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, P = transform_point(&info.transform_3d, P); } - switch (info.data_type) { - case IMAGE_DATA_TYPE_HALF: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_BYTE: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_USHORT: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_FLOAT: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_HALF4: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_BYTE4: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_USHORT4: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - case IMAGE_DATA_TYPE_FLOAT4: - return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); - default: - assert(0); - return make_float4( - TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A); + if (info.sparse_tile_map) { + switch (info.data_type) { + case IMAGE_DATA_TYPE_HALF: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_BYTE: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_USHORT: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_FLOAT: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_HALF4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_BYTE4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_USHORT4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_FLOAT4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_NUM_TYPES: + break; + } + } + else { + switch (info.data_type) { + case IMAGE_DATA_TYPE_HALF: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_BYTE: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_USHORT: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_FLOAT: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_HALF4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_BYTE4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_USHORT4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_TYPE_FLOAT4: + return TextureInterpolator::interp_3d(info, P.x, P.y, P.z, interp); + case IMAGE_DATA_NUM_TYPES: + break; + } } + + return make_float4( + TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A); } } /* Namespace. */ diff --git a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h index 89fcb0ae60f..95bd963c278 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h +++ b/intern/cycles/kernel/kernels/opencl/kernel_opencl_image.h @@ -117,16 +117,8 @@ ccl_device_inline float4 svm_image_texture_read_3d(KernelGlobals *kg, int id, in { const ccl_global TextureInfo *info = kernel_tex_info(kg, id); - /* Wrap */ - if (info->extension == EXTENSION_REPEAT) { - x = svm_image_texture_wrap_periodic(x, info->width); - y = svm_image_texture_wrap_periodic(y, info->height); - z = svm_image_texture_wrap_periodic(z, info->depth); - } - else { - x = svm_image_texture_wrap_clamp(x, info->width); - y = svm_image_texture_wrap_clamp(y, info->height); - z = svm_image_texture_wrap_clamp(z, info->depth); + if (x < 0 || x >= info->width || y < 0 || y >= info->height || z < 0 || z >= info->depth) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); } int offset = x + info->width * y + info->width * info->height * z; @@ -215,12 +207,6 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float3 P const float y = P.y; const float z = P.z; - if (info->extension == EXTENSION_CLIP) { - if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - } - uint interpolation = (interp == INTERPOLATION_NONE) ? info->interpolation : interp; if (interpolation == INTERPOLATION_CLOSEST) { diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 5a02647ef55..43234fd0b2b 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -181,6 +181,7 @@ ImageMetaData::ImageMetaData() height(0), depth(0), type(IMAGE_DATA_NUM_TYPES), + sparse(false), colorspace(u_colorspace_raw), colorspace_file_format(""), use_transform_3d(false), @@ -188,14 +189,6 @@ ImageMetaData::ImageMetaData() { } -bool ImageMetaData::operator==(const ImageMetaData &other) const -{ - return channels == other.channels && width == other.width && height == other.height && - depth == other.depth && use_transform_3d == other.use_transform_3d && - (!use_transform_3d || transform_3d == other.transform_3d) && type == other.type && - colorspace == other.colorspace && compress_as_srgb == other.compress_as_srgb; -} - bool ImageMetaData::is_float() const { return (type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4 || @@ -449,11 +442,22 @@ bool ImageManager::file_load_image(Image *img, int texture_limit) } /* Get metadata. */ - int width = img->metadata.width; - int height = img->metadata.height; - int depth = img->metadata.depth; + int width, height, depth; int components = img->metadata.channels; + if (!img->metadata.sparse) { + /* Regular image storage. */ + width = img->metadata.width; + height = img->metadata.height; + depth = img->metadata.depth; + } + else { + /* Sparse image storage with tiles packed one after the other along with. */ + width = TEXTURE_SPARSE_TILE_DIM * img->metadata.num_sparse_tiles; + height = TEXTURE_SPARSE_TILE_DIM; + depth = TEXTURE_SPARSE_TILE_DIM; + } + /* Read pixels. */ vector pixels_storage; StorageType *pixels; @@ -464,7 +468,8 @@ bool ImageManager::file_load_image(Image *img, int texture_limit) } /* Allocate memory as needed, may be smaller to resize down. */ - if (texture_limit > 0 && max_size > texture_limit) { + if (!img->metadata.sparse && texture_limit > 0 && max_size > texture_limit) { + /* TODO: sparse support. */ pixels_storage.resize(((size_t)width) * height * depth * 4); pixels = &pixels_storage[0]; } @@ -482,6 +487,10 @@ bool ImageManager::file_load_image(Image *img, int texture_limit) img->loader->load_pixels( img->metadata, pixels, num_pixels * components, image_associate_alpha(img)); + if (img->metadata.sparse) { + img->mem->alloc_sparse_tile_map(img->metadata.sparse_tile_map); + } + /* The kernel can handle 1 and 4 channel images. Anything that is not a single * channel image is converted to RGBA format. */ bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 || diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 00ab12afd7a..4e46418642a 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -78,6 +78,10 @@ class ImageMetaData { size_t width, height, depth; ImageDataType type; + bool sparse; + size_t num_sparse_tiles; + vector sparse_tile_map; + /* Optional color space, defaults to raw. */ ustring colorspace; const char *colorspace_file_format; @@ -90,7 +94,6 @@ class ImageMetaData { bool compress_as_srgb; ImageMetaData(); - bool operator==(const ImageMetaData &other) const; bool is_float() const; void detect_colorspace(); }; diff --git a/intern/cycles/render/image_vdb.cpp b/intern/cycles/render/image_vdb.cpp index 37959150757..3cd82905252 100644 --- a/intern/cycles/render/image_vdb.cpp +++ b/intern/cycles/render/image_vdb.cpp @@ -31,57 +31,127 @@ VDBImageLoader::~VDBImageLoader() { } -bool VDBImageLoader::load_metadata(ImageMetaData &metadata) +template +static void sparse_grid_metadata(const GridType &grid, + openvdb::CoordBBox &bbox, + ImageMetaData &metadata) { -#ifdef WITH_OPENVDB - if (!grid) { - return false; - } + using TreeType = typename GridType::TreeType; + using LeafCIter = typename TreeType::LeafCIter; + using LeafNodeType = typename TreeType::LeafNodeType; - bbox = grid->evalActiveVoxelBoundingBox(); + grid.tree().evalLeafBoundingBox(bbox); if (bbox.empty()) { - return false; + return; } - /* Set dimensions. */ openvdb::Coord dim = bbox.dim(); openvdb::Coord min = bbox.min(); + + /* OpenVDB leaf nodes and our tile sizes must match.*/ + assert(dim.x() % TEXTURE_SPARSE_TILE_DIM == 0); + assert(dim.y() % TEXTURE_SPARSE_TILE_DIM == 0); + assert(dim.z() % TEXTURE_SPARSE_TILE_DIM == 0); + dim.x() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + dim.y() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + dim.z() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + metadata.width = dim.x(); metadata.height = dim.y(); metadata.depth = dim.z(); + metadata.sparse = true; + + /* Compute offsets for active tiles. */ + metadata.sparse_tile_map.resize(dim.x() * dim.y() * dim.z(), TEXTURE_SPARSE_TILE_NONE); + uint *tile_map = metadata.sparse_tile_map.data(); + + uint tile_offset = 0; + for (LeafCIter iter = grid.tree().cbeginLeaf(); iter; ++iter) { + const LeafNodeType &leaf = *iter; + openvdb::Coord tile = leaf.getNodeBoundingBox().min() - min; + tile.x() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + tile.y() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + tile.z() >>= TEXTURE_SPARSE_TILE_LOG2DIM; + tile_map[tile.x() + tile.y() * dim.x() + tile.z() * dim.x() * dim.y()] = tile_offset++; + } + + metadata.num_sparse_tiles = tile_offset; +} + +template +static void sparse_grid_pixels(const GridType &grid, StorageType *pixels) +{ + /* TODO: how to handle active tiles? */ + /* TODO: implement threshold. */ + /* TODO: reference memory rather than copy. */ + using LeafCIter = typename GridType::TreeType::LeafCIter; + using LeafNodeType = typename GridType::TreeType::LeafNodeType; + using ValueType = typename GridType::ValueType; + + for (LeafCIter iter = grid.tree().cbeginLeaf(); iter; ++iter) { + const LeafNodeType &leaf = *iter; + const ValueType *data = leaf.buffer().data(); + + /* TODO: order correct? */ + for (int i = 0; i < TEXTURE_SPARSE_TILE_SIZE_3D; i++, pixels++, data++) { + *pixels = StorageType(*data); + } + } +} - /* Set data type. */ +bool VDBImageLoader::load_metadata(ImageMetaData &metadata) +{ +#ifdef WITH_OPENVDB + if (!grid) { + return false; + } + + /* Get channels, dimensions and tiles from supported grid types. */ if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 3; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 3; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 3; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else if (grid->isType()) { metadata.channels = 1; + sparse_grid_metadata(*openvdb::gridConstPtrCast(grid), bbox, metadata); } else { return false; } + if (bbox.empty()) { + return false; + } + + /* Set datatype. */ if (metadata.channels == 1) { metadata.type = IMAGE_DATA_TYPE_FLOAT; } @@ -98,6 +168,8 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata) } } + openvdb::Coord dim = bbox.dim(); + openvdb::Coord min = bbox.min(); Transform texture_to_index = transform_translate(min.x(), min.y(), min.z()) * transform_scale(dim.x(), dim.y(), dim.z()); @@ -117,44 +189,35 @@ bool VDBImageLoader::load_pixels(const ImageMetaData &metadata, const bool associate_alpha) { if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); } else if (grid->isType()) { - openvdb::tools::Dense dense( - bbox, (openvdb::Vec3f *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); - } - else if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), + (openvdb::Vec3f *)pixels); } + /* TODO else if (grid->isType()) { + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); + }*/ else if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); } else if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); } else if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); } else if (grid->isType()) { - openvdb::tools::Dense dense( - bbox, (openvdb::Vec3f *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), + (openvdb::Vec3f *)pixels); } else if (grid->isType()) { - openvdb::tools::Dense dense( - bbox, (openvdb::Vec3f *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); - } - else if (grid->isType()) { - openvdb::tools::Dense dense(bbox, (float *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), + (openvdb::Vec3f *)pixels); } + /* TODO else if (grid->isType()) { + sparse_grid_pixels(*openvdb::gridConstPtrCast(grid), (float *)pixels); + }*/ return true; } diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index 863c2ea3124..2fbcc05af93 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -101,11 +101,43 @@ typedef struct TextureInfo { uint interpolation, extension; /* Dimensions. */ uint width, height, depth; + uint pad[2]; + /* Sparse 3D tiles. */ + uint64_t sparse_tile_map; /* Transform for 3D textures. */ uint use_transform_3d; Transform transform_3d; } TextureInfo; +/* Sparse Textures */ +#define TEXTURE_SPARSE_TILE_LOG2DIM 3 +#define TEXTURE_SPARSE_TILE_DIM (1 << TEXTURE_SPARSE_TILE_LOG2DIM) +#define TEXTURE_SPARSE_TILE_SIZE_3D \ + (TEXTURE_SPARSE_TILE_DIM * TEXTURE_SPARSE_TILE_DIM * TEXTURE_SPARSE_TILE_DIM) +#define TEXTURE_SPARSE_TILE_NONE (~0) + +ccl_device_inline uint texture_sparse_tile_index_3d( + const int width, const int height, const int depth, const int x, const int y, const int z) +{ + const int tile_x = x >> TEXTURE_SPARSE_TILE_LOG2DIM; + const int tile_y = y >> TEXTURE_SPARSE_TILE_LOG2DIM; + const int tile_z = z >> TEXTURE_SPARSE_TILE_LOG2DIM; + + if (tile_x < 0 || tile_x >= width || tile_y < 0 || tile_y >= height || tile_z < 0 || + tile_z >= depth) { + return TEXTURE_SPARSE_TILE_NONE; + } + + return tile_x + width * (tile_y + height * tile_z) * height; +} + +ccl_device_inline int texture_sparse_voxel_index_3d(const int x, const int y, const int z) +{ + return (x & (TEXTURE_SPARSE_TILE_DIM - 1)) + + (y & (TEXTURE_SPARSE_TILE_DIM - 1)) * TEXTURE_SPARSE_TILE_DIM + + (z & (TEXTURE_SPARSE_TILE_DIM - 1)) * TEXTURE_SPARSE_TILE_DIM * TEXTURE_SPARSE_TILE_DIM; +} + CCL_NAMESPACE_END #endif /* __UTIL_TEXTURE_H__ */