24# include <OSL/oslexec.h>
51 return "nanovdb_float";
53 return "nanovdb_float3";
57 return "nanovdb_fp16";
59 assert(!
"System enumerator type, should never be used");
62 assert(!
"Unhandled image data type");
73 : tile_slots(other.tile_slots), manager(other.manager)
102 manager->remove_image_user(slot);
126 manager->load_image_metadata(img);
136 if (
manager->osl_texture_system) {
151 svm_slots.reserve(num_nodes);
152 for (
size_t i = 0; i < num_nodes; i++) {
156 node.x =
manager->images[slot]->loader->get_tile_number();
161 node.z =
manager->images[slot]->loader->get_tile_number();
169 svm_slots.push_back(node);
199 if (loader ==
NULL) {
230 colorspace_file_format(
""),
231 use_transform_3d(
false),
232 compress_as_srgb(
false)
238 return channels == other.channels &&
width == other.width &&
height == other.height &&
296 return (a &&
b &&
typeid(*a) ==
typeid(*
b) && a->equals(*
b));
310 osl_texture_system =
NULL;
319 for (
size_t slot = 0; slot < images.size(); slot++) {
320 assert(!images[slot]);
326 osl_texture_system = texture_system;
331 if (frame != animation_frame) {
333 animation_frame = frame;
335 for (
size_t slot = 0; slot < images.size(); slot++) {
336 if (images[slot] && images[slot]->
params.animated) {
345void ImageManager::load_image_metadata(
Image *img)
347 if (!img->need_metadata) {
352 if (!img->need_metadata) {
360 if (img->loader->load_metadata(features, metadata)) {
374 img->need_metadata =
false;
383 handle.manager =
this;
395 string tile_filename = filename;
402 int u = ((
tile - 1001) % 10);
403 int v = ((
tile - 1001) / 10);
407 handle.tile_slots.push_back(slot);
417 const size_t slot = add_image_slot(loader,
params, builtin);
421 handle.manager =
this;
430 const size_t slot = add_image_slot(loader,
params,
true);
431 handle.tile_slots.push_back(slot);
434 handle.manager =
this;
438size_t ImageManager::add_image_slot(
ImageLoader *loader,
448 for (slot = 0; slot < images.size(); slot++) {
458 for (slot = 0; slot < images.size(); slot++) {
464 if (slot == images.size()) {
465 images.resize(images.size() + 1);
471 img->loader = loader;
472 img->need_metadata =
true;
473 img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
474 img->builtin = builtin;
485void ImageManager::add_image_user(
size_t slot)
488 Image *image = images[slot];
489 assert(image && image->users >= 1);
494void ImageManager::remove_image_user(
size_t slot)
497 Image *image = images[slot];
498 assert(image && image->users >= 1);
506 if (image->users == 0) {
520template<TypeDesc::BASETYPE FileFormat,
typename StorageType>
521bool ImageManager::file_load_image(
Image *img,
int texture_limit)
524 if (!(img->metadata.channels > 0)) {
529 int width = img->metadata.width;
530 int height = img->metadata.height;
531 int depth = img->metadata.depth;
532 int components = img->metadata.channels;
537 const size_t max_size =
max(
max(width, height), depth);
544 if (texture_limit > 0 && max_size > texture_limit) {
545 pixels_storage.resize(((
size_t)width) * height * depth * 4);
546 pixels = &pixels_storage[0];
550 pixels = (StorageType *)img->mem->alloc(width, height, depth);
553 if (pixels ==
NULL) {
558 const size_t num_pixels = ((size_t)width) * height * depth;
559 img->loader->load_pixels(
572 if (components == 2) {
574 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
575 pixels[i * 4 + 3] = pixels[i * 2 + 1];
576 pixels[i * 4 + 2] = pixels[i * 2 + 0];
577 pixels[i * 4 + 1] = pixels[i * 2 + 0];
578 pixels[i * 4 + 0] = pixels[i * 2 + 0];
581 else if (components == 3) {
583 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
584 pixels[i * 4 + 3] = one;
585 pixels[i * 4 + 2] = pixels[i * 3 + 2];
586 pixels[i * 4 + 1] = pixels[i * 3 + 1];
587 pixels[i * 4 + 0] = pixels[i * 3 + 0];
590 else if (components == 1) {
592 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
593 pixels[i * 4 + 3] = one;
594 pixels[i * 4 + 2] = pixels[i];
595 pixels[i * 4 + 1] = pixels[i];
596 pixels[i * 4 + 0] = pixels[i];
602 for (
size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
603 pixels[i * 4 + 3] = one;
613 img->metadata.colorspace, pixels, num_pixels, is_rgba, img->metadata.compress_as_srgb);
617 if constexpr (FileFormat == TypeDesc::FLOAT) {
622 for (
size_t i = 0; i < num_pixels; i += 4) {
623 StorageType *pixel = &pixels[i * 4];
624 if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) ||
635 for (
size_t i = 0; i < num_pixels; ++i) {
636 StorageType *pixel = &pixels[i];
637 if (!isfinite(pixel[0])) {
645 if (pixels_storage.size() > 0) {
646 float scale_factor = 1.0f;
647 while (max_size * scale_factor > texture_limit) {
648 scale_factor *= 0.5f;
650 VLOG_WORK <<
"Scaling image " << img->loader->name() <<
" by a factor of " << scale_factor
653 size_t scaled_width, scaled_height, scaled_depth;
665 StorageType *texture_pixels;
669 texture_pixels = (StorageType *)img->mem->alloc(scaled_width, scaled_height, scaled_depth);
672 memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() *
sizeof(StorageType));
678void ImageManager::device_load_image(
Device *device,
Scene *scene,
size_t slot,
Progress *progress)
684 Image *img = images[slot];
686 progress->
set_status(
"Updating Images",
"Loading " + img->loader->name());
688 const int texture_limit = scene->params.texture_limit;
690 load_image_metadata(img);
704 device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
705 img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
706 img->mem->info.transform_3d = img->metadata.transform_3d;
710 if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
713 float *pixels = (
float *)img->mem->alloc(1, 1);
722 if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
725 float *pixels = (
float *)img->mem->alloc(1, 1);
731 if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
734 uchar *pixels = (
uchar *)img->mem->alloc(1, 1);
743 if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
746 uchar *pixels = (
uchar *)img->mem->alloc(1, 1);
752 if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
755 half *pixels = (
half *)img->mem->alloc(1, 1);
764 if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
773 if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
785 if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
788 half *pixels = (
half *)img->mem->alloc(1, 1);
798 void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
800 if (pixels !=
NULL) {
801 img->loader->load_pixels(img->metadata, pixels, img->metadata.byte_size,
false);
808 img->mem->copy_to_device();
812 img->loader->cleanup();
813 img->need_load =
false;
816void ImageManager::device_free_image(
Device *,
size_t slot)
818 Image *img = images[slot];
823 if (osl_texture_system) {
825 ustring filepath = img->loader->osl_filepath();
826 if (!filepath.empty()) {
827 ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
849 if (scene->update_stats) {
850 scene->update_stats->image.times.add_entry({
"device_update", time});
855 for (
size_t slot = 0; slot < images.size(); slot++) {
856 Image *img = images[slot];
857 if (img && img->users == 0) {
858 device_free_image(device, slot);
860 else if (img && img->need_load) {
862 function_bind(&ImageManager::device_load_image,
this, device, scene, slot, &progress));
868 need_update_ =
false;
876 Image *img = images[slot];
879 if (img->
users == 0) {
880 device_free_image(device, slot);
883 device_load_image(device, scene, slot, progress);
896 for (
size_t slot = 0; slot < images.size(); slot++) {
897 Image *img = images[slot];
900 function_bind(&ImageManager::device_load_image,
this, device, scene, slot, &progress));
909 for (
size_t slot = 0; slot < images.size(); slot++) {
910 Image *img = images[slot];
912 device_free_image(device, slot);
919 for (
size_t slot = 0; slot < images.size(); slot++) {
920 device_free_image(device, slot);
927 foreach (
const Image *image, images) {
933 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, size_t num_pixels, bool is_rgba, bool compress_as_srgb)
vector< size_t > tile_slots
ImageManager * get_manager() const
bool operator==(const ImageHandle &other) const
VDBImageLoader * vdb_loader(const int tile_index=0) const
device_texture * image_memory(const int tile_index=0) const
ImageHandle & operator=(const ImageHandle &other)
int svm_slot(const int tile_index=0) const
vector< int4 > get_svm_slots() 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
bool set_animation_frame_update(int frame)
ImageManager(const DeviceInfo &info)
void device_update(Device *device, Scene *scene, Progress &progress)
void device_free(Device *device)
void device_update_slot(Device *device, Scene *scene, size_t slot, Progress *progress)
void device_load_builtin(Device *device, Scene *scene, Progress &progress)
void device_free_builtin(Device *device)
ImageHandle add_image(const string &filename, const ImageParams ¶ms)
void collect_statistics(RenderStats *stats)
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_="")
ustring u_colorspace_srgb
local_group_size(16, 16) .push_constant(Type b
T util_image_cast_from_float(float value)
CCL_NAMESPACE_BEGIN OIIO_NAMESPACE_USING void util_image_resize_pixels(const vector< T > &input_pixels, const size_t input_width, const size_t input_height, const size_t input_depth, const size_t components, vector< T > *output_pixels, size_t *output_width, size_t *output_height, size_t *output_depth)
#define CCL_NAMESPACE_END
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
ccl_global const KernelWorkTile * tile
const char * name_from_type(ImageDataType type)
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)
void push(TaskRunFunction &&task)
void wait_work(Summary *stats=NULL)
std::unique_lock< std::mutex > thread_scoped_lock
@ IMAGE_DATA_TYPE_NANOVDB_FP16
@ IMAGE_DATA_TYPE_USHORT4
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
@ IMAGE_DATA_TYPE_NANOVDB_FPN
@ IMAGE_ALPHA_CHANNEL_PACKED
#define TEX_IMAGE_MISSING_R
#define TEX_IMAGE_MISSING_B
#define TEX_IMAGE_MISSING_A
#define TEX_IMAGE_MISSING_G
ccl_device_inline size_t divide_up(size_t x, size_t y)