21# include <OSL/oslexec.h>
48 return "nanovdb_float";
50 return "nanovdb_float3";
52 return "nanovdb_float4";
56 return "nanovdb_fp16";
58 return "nanovdb_empty";
60 assert(!
"System enumerator type, should never be used");
63 assert(!
"Unhandled image data type");
77 for (
const size_t slot :
slots) {
89 for (
const size_t slot :
slots) {
103 for (
const size_t slot :
slots) {
104 manager->remove_image_user(slot);
113 return slots.empty();
133 manager->load_image_metadata(img);
139 if (slot_index >=
slots.size()) {
143 if (
manager->osl_texture_system) {
145 if (!img->
loader->osl_filepath().empty()) {
150 return slots[slot_index];
158 svm_slots.reserve(num_nodes);
159 for (
size_t i = 0;
i < num_nodes;
i++) {
162 size_t slot =
slots[2 *
i];
163 node.
x =
manager->get_image_slot(slot)->loader->get_tile_number();
166 if ((2 *
i + 1) <
slots.size()) {
168 node.
z =
manager->get_image_slot(slot)->loader->get_tile_number();
176 svm_slots.push_back(node);
189 return img ? img->
mem.get() :
nullptr;
200 if (img ==
nullptr) {
206 if (loader ==
nullptr) {
298 if (a ==
nullptr &&
b ==
nullptr) {
301 return (a &&
b &&
typeid(*a) ==
typeid(*
b) && a->
equals(*
b));
314 osl_texture_system =
nullptr;
323 for (
size_t slot = 0; slot < images.size(); slot++) {
330 osl_texture_system = texture_system;
335 if (frame != animation_frame) {
337 animation_frame = frame;
339 for (
size_t slot = 0; slot < images.size(); slot++) {
340 if (images[slot] && images[slot]->
params.animated) {
349void ImageManager::load_image_metadata(
Image *img)
351 if (!img->need_metadata) {
356 if (!img->need_metadata) {
360 ImageMetaData &metadata = img->metadata;
361 metadata = ImageMetaData();
364 if (img->loader->load_metadata(features, metadata)) {
375 img->need_metadata =
false;
380 const size_t slot = add_image_slot(make_unique<OIIOImageLoader>(filename),
params,
false);
383 handle.
slots.push_back(slot);
397 const size_t slot = add_image_slot(make_unique<OIIOImageLoader>(filename),
params,
false);
398 handle.
slots.push_back(slot);
403 string tile_filename = filename;
409 const int u = ((
tile - 1001) % 10);
410 const int v = ((
tile - 1001) / 10);
413 const size_t slot = add_image_slot(make_unique<OIIOImageLoader>(tile_filename),
params,
false);
414 handle.
slots.push_back(slot);
424 const size_t slot = add_image_slot(std::move(loader),
params, builtin);
427 handle.
slots.push_back(slot);
440 std::swap(loader, local_loader);
441 const size_t slot = add_image_slot(std::move(local_loader),
params,
true);
442 handle.
slots.push_back(slot);
458 for (slot = 0; slot < images.size(); slot++) {
459 Image *img = images[slot].get();
467 for (slot = 0; slot < images.size(); slot++) {
473 if (slot == images.size()) {
474 images.resize(images.size() + 1);
478 unique_ptr<Image> img = make_unique<Image>();
480 img->loader = std::move(loader);
481 img->need_metadata =
true;
482 img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
483 img->builtin = builtin;
487 images[slot] = std::move(img);
494void ImageManager::add_image_user(
const size_t slot)
497 Image *image = images[slot].get();
498 assert(image && image->users >= 1);
503void ImageManager::remove_image_user(
const size_t slot)
506 Image *image = images[slot].get();
507 assert(image && image->users >= 1);
515 if (image->users == 0) {
524 return images[slot].get();
536template<TypeDesc::BASETYPE FileFormat,
typename StorageType>
537bool ImageManager::file_load_image(
Image *img,
const int texture_limit)
540 if (!(img->metadata.channels > 0)) {
545 const int width = img->metadata.width;
546 const int height = img->metadata.height;
547 const int components = img->metadata.channels;
550 vector<StorageType> pixels_storage;
552 const size_t max_size =
max(width, height);
559 if (texture_limit > 0 && max_size > texture_limit) {
560 pixels_storage.resize(((
size_t)width) * height * 4);
561 pixels = &pixels_storage[0];
565 pixels = (StorageType *)img->mem->alloc(width, height);
568 if (pixels ==
nullptr) {
573 const size_t num_pixels = ((size_t)width) * height;
574 img->loader->load_pixels(
587 if (components == 2) {
589 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++,
i--) {
590 pixels[
i * 4 + 3] = pixels[
i * 2 + 1];
591 pixels[
i * 4 + 2] = pixels[
i * 2 + 0];
592 pixels[
i * 4 + 1] = pixels[
i * 2 + 0];
593 pixels[
i * 4 + 0] = pixels[
i * 2 + 0];
596 else if (components == 3) {
598 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++,
i--) {
599 pixels[
i * 4 + 3] = one;
600 pixels[
i * 4 + 2] = pixels[
i * 3 + 2];
601 pixels[
i * 4 + 1] = pixels[
i * 3 + 1];
602 pixels[
i * 4 + 0] = pixels[
i * 3 + 0];
605 else if (components == 1) {
607 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++,
i--) {
608 pixels[
i * 4 + 3] = one;
609 pixels[
i * 4 + 2] = pixels[
i];
610 pixels[
i * 4 + 1] = pixels[
i];
611 pixels[
i * 4 + 0] = pixels[
i];
617 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++,
i--) {
618 pixels[
i * 4 + 3] = one;
633 img->metadata.compress_as_srgb,
638 if constexpr (FileFormat == TypeDesc::FLOAT) {
643 for (
size_t i = 0;
i < num_pixels;
i += 4) {
644 StorageType *pixel = &pixels[
i * 4];
645 if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) ||
656 for (
size_t i = 0;
i < num_pixels; ++
i) {
657 StorageType *pixel = &pixels[
i];
658 if (!isfinite(pixel[0])) {
666 if (!pixels_storage.empty()) {
667 float scale_factor = 1.0f;
668 while (max_size * scale_factor > texture_limit) {
669 scale_factor *= 0.5f;
671 LOG_DEBUG <<
"Scaling image " << img->loader->name() <<
" by a factor of " << scale_factor
673 vector<StorageType> scaled_pixels;
675 size_t scaled_height;
685 StorageType *texture_pixels;
689 texture_pixels = (StorageType *)img->mem->alloc(scaled_width, scaled_height);
692 memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() *
sizeof(StorageType));
698void ImageManager::device_load_image(
Device *device,
707 Image *img = images[slot].get();
709 progress.
set_status(
"Updating Images",
"Loading " + img->loader->name());
713 load_image_metadata(img);
725 img->mem = make_unique<device_texture>(
726 device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
727 img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
728 img->mem->info.transform_3d = img->metadata.transform_3d;
732 if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
735 float *pixels = (
float *)img->mem->alloc(1, 1);
744 if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
747 float *pixels = (
float *)img->mem->alloc(1, 1);
753 if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
756 uchar *pixels = (
uchar *)img->mem->alloc(1, 1);
765 if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
768 uchar *pixels = (
uchar *)img->mem->alloc(1, 1);
774 if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
777 half *pixels = (
half *)img->mem->alloc(1, 1);
786 if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
795 if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
807 if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
810 half *pixels = (
half *)img->mem->alloc(1, 1);
818 void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
820 if (pixels !=
nullptr) {
821 img->loader->load_pixels(img->metadata, pixels, img->metadata.byte_size,
false);
828 img->mem->copy_to_device();
832 img->loader->cleanup();
833 img->need_load =
false;
836void ImageManager::device_free_image(
Device * ,
size_t slot)
838 Image *img = images[slot].get();
839 if (img ==
nullptr) {
843 if (osl_texture_system) {
845 const ustring filepath = img->loader->osl_filepath();
846 if (!filepath.empty()) {
847 ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
857 images[slot].reset();
868 scene->
update_stats->image.times.add_entry({
"device_update", time});
873 for (
size_t slot = 0; slot < images.size(); slot++) {
874 Image *img = images[slot].get();
875 if (img && img->
users == 0) {
876 device_free_image(device, slot);
879 pool.push([
this, device, scene, slot, &progress] {
880 device_load_image(device, scene, slot, progress);
887 need_update_ =
false;
895 Image *img = images[slot].get();
898 if (img->
users == 0) {
899 device_free_image(device, slot);
902 device_load_image(device, scene, slot, progress);
915 for (
size_t slot = 0; slot < images.size(); slot++) {
916 Image *img = images[slot].get();
918 pool.
push([
this, device, scene, slot, &progress] {
919 device_load_image(device, scene, slot, progress);
929 for (
size_t slot = 0; slot < images.size(); slot++) {
930 Image *img = images[slot].get();
932 device_free_image(device, slot);
939 for (
size_t slot = 0; slot < images.size(); slot++) {
940 device_free_image(device, slot);
953 NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
ATTR_WARN_UNUSED_RESULT const BMVert * v
static bool colorspace_is_data(ustring colorspace)
static ustring detect_known_colorspace(ustring colorspace, const char *file_colorspace, const char *file_format, bool is_float)
static void to_scene_linear(ustring colorspace, T *pixels, const size_t num_pixels, bool is_rgba, bool compress_as_srgb, bool ignore_alpha)
ImageManager * get_manager() const
bool operator==(const ImageHandle &other) const
friend class ImageManager
ImageHandle & operator=(const ImageHandle &other)
VDBImageLoader * vdb_loader() const
device_texture * image_memory() const
int num_svm_slots() const
vector< int4 > get_svm_slots() const
int svm_slot(const int slot_index=0) const
virtual bool equals(const ImageLoader &other) const =0
virtual ustring osl_filepath() const
virtual int get_tile_number() const
virtual bool is_vdb_loader() const
ImageManager(const DeviceInfo &info)
void device_update(Device *device, Scene *scene, Progress &progress)
void device_free(Device *device)
void device_load_builtin(Device *device, Scene *scene, Progress &progress)
bool set_animation_frame_update(const int frame)
void device_free_builtin(Device *device)
ImageHandle add_image(const string &filename, const ImageParams ¶ms)
void collect_statistics(RenderStats *stats)
void device_update_slot(Device *device, Scene *scene, const size_t slot, Progress &progress)
void set_osl_texture_system(void *texture_system)
ImageAlphaType alpha_type
void add_entry(const NamedSizeEntry &entry)
void set_status(const string &status_, const string &substatus_="")
T util_image_cast_from_float(const float value)
void util_image_resize_pixels(const vector< T > &input_pixels, const size_t input_width, const size_t input_height, const size_t components, vector< T > *output_pixels, size_t *output_width, size_t *output_height)
#define CCL_NAMESPACE_END
#define assert(assertion)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
const ccl_global KernelWorkTile * tile
const char * name_from_type(ImageDataType type)
ustring u_colorspace_srgb
static bool image_associate_alpha(ImageManager::Image *img)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
void string_replace(string &haystack, const string &needle, const string &other)
unique_ptr< device_texture > mem
unique_ptr< ImageLoader > loader
unique_ptr< SceneUpdateStats > update_stats
void push(TaskRunFunction &&task)
void wait_work(Summary *stats=nullptr)
@ IMAGE_DATA_TYPE_NANOVDB_FP16
@ IMAGE_DATA_TYPE_USHORT4
@ IMAGE_DATA_TYPE_NANOVDB_EMPTY
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT4
@ IMAGE_DATA_TYPE_NANOVDB_FPN
@ IMAGE_ALPHA_CHANNEL_PACKED
ccl_device_inline bool is_nanovdb_type(int type)
std::unique_lock< std::mutex > thread_scoped_lock
ccl_device_inline size_t divide_up(const size_t x, const size_t y)