diff options
Diffstat (limited to 'intern/cycles/render/image.cpp')
-rw-r--r-- | intern/cycles/render/image.cpp | 768 |
1 files changed, 312 insertions, 456 deletions
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index e5fb2fcaf3d..b4539b5ce3c 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -15,12 +15,14 @@ */ #include "render/image.h" +#include "render/image_oiio.h" #include "device/device.h" #include "render/colorspace.h" #include "render/scene.h" #include "render/stats.h" #include "util/util_foreach.h" +#include "util/util_image.h" #include "util/util_image_impl.h" #include "util/util_logging.h" #include "util/util_path.h" @@ -50,21 +52,6 @@ bool isfinite(uint16_t /*value*/) return true; } -/* The lower three bits of a device texture slot number indicate its type. - * These functions convert the slot ids from ImageManager "images" ones - * to device ones and vice verse. - */ -int type_index_to_flattened_slot(int slot, ImageDataType type) -{ - return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); -} - -int flattened_slot_to_type_index(int flat_slot, ImageDataType *type) -{ - *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); - return flat_slot >> IMAGE_DATA_TYPE_SHIFT; -} - const char *name_from_type(ImageDataType type) { switch (type) { @@ -94,302 +81,342 @@ const char *name_from_type(ImageDataType type) } // namespace -ImageManager::ImageManager(const DeviceInfo &info) +/* Image Handle */ + +ImageHandle::ImageHandle() : manager(NULL) { - need_update = true; - osl_texture_system = NULL; - animation_frame = 0; +} - /* Set image limits */ - max_num_images = TEX_NUM_MAX; - has_half_images = info.has_half_images; +ImageHandle::ImageHandle(const ImageHandle &other) + : tile_slots(other.tile_slots), manager(other.manager) +{ + /* Increase image user count. */ + foreach (const int slot, tile_slots) { + manager->add_image_user(slot); + } +} - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_num_images[type] = 0; +ImageHandle &ImageHandle::operator=(const ImageHandle &other) +{ + clear(); + manager = other.manager; + tile_slots = other.tile_slots; + + foreach (const int slot, tile_slots) { + manager->add_image_user(slot); } + + return *this; } -ImageManager::~ImageManager() +ImageHandle::~ImageHandle() { - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) - assert(!images[type][slot]); + clear(); +} + +void ImageHandle::clear() +{ + foreach (const int slot, tile_slots) { + manager->remove_image_user(slot); } } -void ImageManager::set_osl_texture_system(void *texture_system) +bool ImageHandle::empty() { - osl_texture_system = texture_system; + return tile_slots.empty(); } -bool ImageManager::set_animation_frame_update(int frame) +int ImageHandle::num_tiles() { - if (frame != animation_frame) { - animation_frame = frame; + return tile_slots.size(); +} - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key.animated) - return true; - } - } +ImageMetaData ImageHandle::metadata() +{ + if (tile_slots.empty()) { + return ImageMetaData(); } - return false; + ImageManager::Image *img = manager->images[tile_slots.front()]; + manager->load_image_metadata(img); + return img->metadata; } -device_memory *ImageManager::image_memory(int flat_slot) +int ImageHandle::svm_slot(const int tile_index) const { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + if (tile_index >= tile_slots.size()) { + return -1; + } - Image *img = images[type][slot]; + if (manager->osl_texture_system) { + ImageManager::Image *img = manager->images[tile_slots[tile_index]]; + if (img->loader->osl_filepath()) { + return -1; + } + } - return img->mem; + return tile_slots[tile_index]; } -bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata) +device_memory *ImageHandle::image_memory(const int tile_index) const { - if (flat_slot == -1) { - return false; + if (tile_index >= tile_slots.size()) { + return NULL; } - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageManager::Image *img = manager->images[tile_slots[tile_index]]; + return img ? img->mem : NULL; +} - Image *img = images[type][slot]; - if (img) { - metadata = img->metadata; - return true; - } +bool ImageHandle::operator==(const ImageHandle &other) const +{ + return manager == other.manager && tile_slots == other.tile_slots; +} - return false; +/* Image MetaData */ + +ImageMetaData::ImageMetaData() + : channels(0), + width(0), + height(0), + depth(0), + type(IMAGE_DATA_NUM_TYPES), + colorspace(u_colorspace_raw), + colorspace_file_format(""), + compress_as_srgb(false) +{ +} + +bool ImageMetaData::operator==(const ImageMetaData &other) const +{ + return channels == other.channels && width == other.width && height == other.height && + depth == other.depth && 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 || + type == IMAGE_DATA_TYPE_HALF || type == IMAGE_DATA_TYPE_HALF4); } -void ImageManager::metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format) +void ImageMetaData::detect_colorspace() { /* Convert used specified color spaces to one we know how to handle. */ - metadata.colorspace = ColorSpaceManager::detect_known_colorspace( - metadata.colorspace, file_format, metadata.is_float || metadata.is_half); + colorspace = ColorSpaceManager::detect_known_colorspace( + colorspace, colorspace_file_format, is_float()); - if (metadata.colorspace == u_colorspace_raw) { + if (colorspace == u_colorspace_raw) { /* Nothing to do. */ } - else if (metadata.colorspace == u_colorspace_srgb) { + else if (colorspace == u_colorspace_srgb) { /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time * for the common case of 8bit sRGB images like PNG. */ - metadata.compress_as_srgb = true; + compress_as_srgb = true; } else { /* Always compress non-raw 8bit images as scene linear + sRGB, as a * heuristic to keep memory usage the same without too much data loss * due to quantization in common cases. */ - metadata.compress_as_srgb = (metadata.type == IMAGE_DATA_TYPE_BYTE || - metadata.type == IMAGE_DATA_TYPE_BYTE4); + compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4); /* If colorspace conversion needed, use half instead of short so we can * represent HDR values that might result from conversion. */ - if (metadata.type == IMAGE_DATA_TYPE_USHORT) { - metadata.type = IMAGE_DATA_TYPE_HALF; + if (type == IMAGE_DATA_TYPE_USHORT) { + type = IMAGE_DATA_TYPE_HALF; } - else if (metadata.type == IMAGE_DATA_TYPE_USHORT4) { - metadata.type = IMAGE_DATA_TYPE_HALF4; + else if (type == IMAGE_DATA_TYPE_USHORT4) { + type = IMAGE_DATA_TYPE_HALF4; } } } -bool ImageManager::get_image_metadata(const ImageKey &key, ImageMetaData &metadata) -{ - metadata = ImageMetaData(); - metadata.colorspace = key.colorspace; +/* Image Loader */ - if (key.builtin_data) { - if (builtin_image_info_cb) { - builtin_image_info_cb(key.filename, key.builtin_data, metadata); - } - else { - return false; - } - - if (metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; - } +ImageLoader::ImageLoader() +{ +} - metadata_detect_colorspace(metadata, ""); +ustring ImageLoader::osl_filepath() const +{ + return ustring(); +} +bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b) +{ + if (a == NULL && b == NULL) { return true; } - - /* Perform preliminary checks, with meaningful logging. */ - if (!path_exists(key.filename)) { - VLOG(1) << "File '" << key.filename << "' does not exist."; - return false; + else { + return (a && b && typeid(*a) == typeid(*b) && a->equals(*b)); } - if (path_is_directory(key.filename)) { - VLOG(1) << "File '" << key.filename << "' is a directory, can't use as image."; - return false; +} + +/* Image Manager */ + +ImageManager::ImageManager(const DeviceInfo &info) +{ + need_update = true; + osl_texture_system = NULL; + animation_frame = 0; + + /* Set image limits */ + has_half_images = info.has_half_images; +} + +ImageManager::~ImageManager() +{ + for (size_t slot = 0; slot < images.size(); slot++) + assert(!images[slot]); +} + +void ImageManager::set_osl_texture_system(void *texture_system) +{ + osl_texture_system = texture_system; +} + +bool ImageManager::set_animation_frame_update(int frame) +{ + if (frame != animation_frame) { + animation_frame = frame; + + for (size_t slot = 0; slot < images.size(); slot++) { + if (images[slot] && images[slot]->params.animated) + return true; + } } - unique_ptr<ImageInput> in(ImageInput::create(key.filename)); + return false; +} - if (!in) { - return false; +void ImageManager::load_image_metadata(Image *img) +{ + if (!img->need_metadata) { + return; } - ImageSpec spec; - if (!in->open(key.filename, spec)) { - return false; + thread_scoped_lock image_lock(img->mutex); + if (!img->need_metadata) { + return; } - metadata.width = spec.width; - metadata.height = spec.height; - metadata.depth = spec.depth; - metadata.compress_as_srgb = false; + ImageMetaData &metadata = img->metadata; + metadata = ImageMetaData(); + metadata.colorspace = img->params.colorspace; - /* Check the main format, and channel formats. */ - size_t channel_size = spec.format.basesize(); + img->loader->load_metadata(metadata); - if (spec.format.is_floating_point()) { - metadata.is_float = true; - } + metadata.detect_colorspace(); - for (size_t channel = 0; channel < spec.channelformats.size(); channel++) { - channel_size = max(channel_size, spec.channelformats[channel].basesize()); - if (spec.channelformats[channel].is_floating_point()) { - metadata.is_float = true; + /* No half textures on OpenCL, use full float instead. */ + if (!has_half_images) { + if (metadata.type == IMAGE_DATA_TYPE_HALF4) { + metadata.type = IMAGE_DATA_TYPE_FLOAT4; + } + else if (metadata.type == IMAGE_DATA_TYPE_HALF) { + metadata.type = IMAGE_DATA_TYPE_FLOAT; } } - /* check if it's half float */ - if (spec.format == TypeDesc::HALF) { - metadata.is_half = true; - } + img->need_metadata = false; +} - /* set type and channels */ - metadata.channels = spec.nchannels; +ImageHandle ImageManager::add_image(const string &filename, const ImageParams ¶ms) +{ + const int slot = add_image_slot(new OIIOImageLoader(filename), params, false); - if (metadata.is_half) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; - } - else if (metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; - } - else if (spec.format == TypeDesc::USHORT) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + ImageHandle handle; + handle.tile_slots.push_back(slot); + handle.manager = this; + return handle; +} + +ImageHandle ImageManager::add_image(const string &filename, + const ImageParams ¶ms, + const vector<int> &tiles) +{ + ImageHandle handle; + handle.manager = this; + + foreach (int tile, tiles) { + string tile_filename = filename; + if (tile != 0) { + string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile)); + } + const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false); + handle.tile_slots.push_back(slot); } - metadata_detect_colorspace(metadata, in->format_name()); + return handle; +} - in->close(); +ImageHandle ImageManager::add_image(ImageLoader *loader, const ImageParams ¶ms) +{ + const int slot = add_image_slot(loader, params, true); - return true; + ImageHandle handle; + handle.tile_slots.push_back(slot); + handle.manager = this; + return handle; } -int ImageManager::add_image(const ImageKey &key, float frame, ImageMetaData &metadata) +int ImageManager::add_image_slot(ImageLoader *loader, + const ImageParams ¶ms, + const bool builtin) { Image *img; size_t slot; - get_image_metadata(key, metadata); - ImageDataType type = metadata.type; - thread_scoped_lock device_lock(device_mutex); - /* No half textures on OpenCL, use full float instead. */ - if (!has_half_images) { - if (type == IMAGE_DATA_TYPE_HALF4) { - type = IMAGE_DATA_TYPE_FLOAT4; - } - else if (type == IMAGE_DATA_TYPE_HALF) { - type = IMAGE_DATA_TYPE_FLOAT; - } - } - /* Fnd existing image. */ - for (slot = 0; slot < images[type].size(); slot++) { - img = images[type][slot]; - if (img && img->key == key) { - if (img->frame != frame) { - img->frame = frame; - img->need_load = true; - } - if (!(img->metadata == metadata)) { - img->metadata = metadata; - img->need_load = true; - } + for (slot = 0; slot < images.size(); slot++) { + img = images[slot]; + if (img && ImageLoader::equals(img->loader, loader) && img->params == params) { img->users++; - return type_index_to_flattened_slot(slot, type); + delete loader; + return slot; } } /* Find free slot. */ - for (slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) + for (slot = 0; slot < images.size(); slot++) { + if (!images[slot]) break; } - /* Count if we're over the limit. - * Very unlikely, since max_num_images is insanely big. But better safe - * than sorry. - */ - int tex_count = 0; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_count += tex_num_images[type]; - } - if (tex_count > max_num_images) { - printf( - "ImageManager::add_image: Reached image limit (%d), " - "skipping '%s'\n", - max_num_images, - key.filename.c_str()); - return -1; - } - - if (slot == images[type].size()) { - images[type].resize(images[type].size() + 1); + if (slot == images.size()) { + images.resize(images.size() + 1); } /* Add new image. */ img = new Image(); - img->key = key; - img->frame = frame; - img->metadata = metadata; - img->need_load = true; + img->params = params; + img->loader = loader; + img->need_metadata = true; + img->need_load = !(osl_texture_system && img->loader->osl_filepath()); + img->builtin = builtin; img->users = 1; img->mem = NULL; - images[type][slot] = img; - - ++tex_num_images[type]; + images[slot] = img; need_update = true; - return type_index_to_flattened_slot(slot, type); + return slot; } -void ImageManager::add_image_user(int flat_slot) +void ImageManager::add_image_user(int slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); - - Image *image = images[type][slot]; + Image *image = images[slot]; assert(image && image->users >= 1); image->users++; } -void ImageManager::remove_image(int flat_slot) +void ImageManager::remove_image_user(int slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); - - Image *image = images[type][slot]; + Image *image = images[slot]; assert(image && image->users >= 1); /* decrement user count */ @@ -402,98 +429,22 @@ void ImageManager::remove_image(int flat_slot) need_update = true; } -void ImageManager::remove_image(const ImageKey &key) -{ - size_t slot; - - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key == key) { - remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type)); - return; - } - } - } -} - -/* TODO(sergey): Deduplicate with the iteration above, but make it pretty, - * without bunch of arguments passing around making code readability even - * more cluttered. - */ -void ImageManager::tag_reload_image(const ImageKey &key) -{ - for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key == key) { - images[type][slot]->need_load = true; - break; - } - } - } -} - static bool image_associate_alpha(ImageManager::Image *img) { /* For typical RGBA images we let OIIO convert to associated alpha, * but some types we want to leave the RGB channels untouched. */ - return !(ColorSpaceManager::colorspace_is_data(img->key.colorspace) || - img->key.alpha_type == IMAGE_ALPHA_IGNORE || - img->key.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED); -} - -bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *in) -{ - if (img->key.filename == "") - return false; - - if (!img->key.builtin_data) { - /* NOTE: Error logging is done in meta data acquisition. */ - if (!path_exists(img->key.filename) || path_is_directory(img->key.filename)) { - return false; - } - - /* load image from file through OIIO */ - *in = unique_ptr<ImageInput>(ImageInput::create(img->key.filename)); - - if (!*in) - return false; - - ImageSpec spec = ImageSpec(); - ImageSpec config = ImageSpec(); - - if (!image_associate_alpha(img)) { - config.attribute("oiio:UnassociatedAlpha", 1); - } - - if (!(*in)->open(img->key.filename, spec, config)) { - return false; - } - } - else { - /* load image using builtin images callbacks */ - if (!builtin_image_info_cb || !builtin_image_pixels_cb) - return false; - } - - /* we only handle certain number of components */ - if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { - if (*in) { - (*in)->close(); - } - return false; - } - - return true; + return !(ColorSpaceManager::colorspace_is_data(img->params.colorspace) || + img->params.alpha_type == IMAGE_ALPHA_IGNORE || + img->params.alpha_type == IMAGE_ALPHA_CHANNEL_PACKED); } template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType> bool ImageManager::file_load_image(Image *img, - ImageDataType type, int texture_limit, device_vector<DeviceType> &tex_img) { - unique_ptr<ImageInput> in = NULL; - if (!file_load_image_generic(img, &in)) { + /* we only handle certain number of components */ + if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { return false; } @@ -527,90 +478,21 @@ bool ImageManager::file_load_image(Image *img, return false; } - bool cmyk = false; const size_t num_pixels = ((size_t)width) * height * depth; - if (in) { - /* Read pixels through OpenImageIO. */ - StorageType *readpixels = pixels; - vector<StorageType> tmppixels; - if (components > 4) { - tmppixels.resize(((size_t)width) * height * components); - readpixels = &tmppixels[0]; - } - - if (depth <= 1) { - size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType); - in->read_image(FileFormat, - (uchar *)readpixels + (height - 1) * scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); - } - else { - in->read_image(FileFormat, (uchar *)readpixels); - } - - if (components > 4) { - size_t dimensions = ((size_t)width) * height; - for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) { - pixels[i * 4 + 3] = tmppixels[i * components + 3]; - pixels[i * 4 + 2] = tmppixels[i * components + 2]; - pixels[i * 4 + 1] = tmppixels[i * components + 1]; - pixels[i * 4 + 0] = tmppixels[i * components + 0]; - } - tmppixels.clear(); - } - - cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; - in->close(); - } - else { - /* Read pixels through callback. */ - if (FileFormat == TypeDesc::FLOAT) { - builtin_image_float_pixels_cb(img->key.filename, - img->key.builtin_data, - 0, /* TODO(lukas): Support tiles here? */ - (float *)&pixels[0], - num_pixels * components, - image_associate_alpha(img), - img->metadata.builtin_free_cache); - } - else if (FileFormat == TypeDesc::UINT8) { - builtin_image_pixels_cb(img->key.filename, - img->key.builtin_data, - 0, /* TODO(lukas): Support tiles here? */ - (uchar *)&pixels[0], - num_pixels * components, - image_associate_alpha(img), - img->metadata.builtin_free_cache); - } - else { - /* TODO(dingto): Support half for ImBuf. */ - } - } + img->loader->load_pixels( + img->metadata, pixels, num_pixels * components, image_associate_alpha(img)); /* 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 = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 || - type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4); + bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 || + img->metadata.type == IMAGE_DATA_TYPE_HALF4 || + img->metadata.type == IMAGE_DATA_TYPE_BYTE4 || + img->metadata.type == IMAGE_DATA_TYPE_USHORT4); if (is_rgba) { const StorageType one = util_image_cast_from_float<StorageType>(1.0f); - if (cmyk) { - /* CMYK to RGBA. */ - for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { - float c = util_image_cast_to_float(pixels[i * 4 + 0]); - float m = util_image_cast_to_float(pixels[i * 4 + 1]); - float y = util_image_cast_to_float(pixels[i * 4 + 2]); - float k = util_image_cast_to_float(pixels[i * 4 + 3]); - pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); - pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); - pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); - pixels[i * 4 + 3] = one; - } - } - else if (components == 2) { + if (components == 2) { /* Grayscale + alpha to RGBA. */ for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i * 4 + 3] = pixels[i * 2 + 1]; @@ -639,7 +521,7 @@ bool ImageManager::file_load_image(Image *img, } /* Disable alpha if requested by the user. */ - if (img->key.alpha_type == IMAGE_ALPHA_IGNORE) { + if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) { for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { pixels[i * 4 + 3] = one; } @@ -686,7 +568,8 @@ bool ImageManager::file_load_image(Image *img, while (max_size * scale_factor > texture_limit) { scale_factor *= 0.5f; } - VLOG(1) << "Scaling image " << img->key.filename << " by a factor of " << scale_factor << "."; + VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor + << "."; vector<StorageType> scaled_pixels; size_t scaled_width, scaled_height, scaled_depth; util_image_resize_pixels(pixels_storage, @@ -716,29 +599,28 @@ bool ImageManager::file_load_image(Image *img, static void image_set_device_memory(ImageManager::Image *img, device_memory *mem) { img->mem = mem; - mem->interpolation = img->key.interpolation; - mem->extension = img->key.extension; + mem->image_data_type = img->metadata.type; + mem->interpolation = img->params.interpolation; + mem->extension = img->params.extension; } -void ImageManager::device_load_image( - Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress) +void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress) { - if (progress->get_cancel()) + if (progress->get_cancel()) { return; + } - Image *img = images[type][slot]; + Image *img = images[slot]; - if (osl_texture_system && !img->key.builtin_data) - return; - - string filename = path_filename(images[type][slot]->key.filename); - progress->set_status("Updating Images", "Loading " + filename); + progress->set_status("Updating Images", "Loading " + img->loader->name()); const int texture_limit = scene->params.texture_limit; + load_image_metadata(img); + ImageDataType type = img->metadata.type; + /* Slot assignment */ - int flat_slot = type_index_to_flattened_slot(slot, type); - img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), flat_slot); + img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot); /* Free previous texture in slot. */ if (img->mem) { @@ -752,7 +634,7 @@ void ImageManager::device_load_image( device_vector<float4> *tex_img = new device_vector<float4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); float *pixels = (float *)tex_img->alloc(1, 1); @@ -772,7 +654,7 @@ void ImageManager::device_load_image( device_vector<float> *tex_img = new device_vector<float>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); float *pixels = (float *)tex_img->alloc(1, 1); @@ -789,7 +671,7 @@ void ImageManager::device_load_image( device_vector<uchar4> *tex_img = new device_vector<uchar4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uchar *pixels = (uchar *)tex_img->alloc(1, 1); @@ -809,7 +691,7 @@ void ImageManager::device_load_image( device_vector<uchar> *tex_img = new device_vector<uchar>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uchar *pixels = (uchar *)tex_img->alloc(1, 1); @@ -826,7 +708,7 @@ void ImageManager::device_load_image( device_vector<half4> *tex_img = new device_vector<half4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); half *pixels = (half *)tex_img->alloc(1, 1); @@ -846,7 +728,7 @@ void ImageManager::device_load_image( device_vector<uint16_t> *tex_img = new device_vector<uint16_t>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); @@ -863,7 +745,7 @@ void ImageManager::device_load_image( device_vector<ushort4> *tex_img = new device_vector<ushort4>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); @@ -883,7 +765,7 @@ void ImageManager::device_load_image( device_vector<half> *tex_img = new device_vector<half>( device, img->mem_name.c_str(), MEM_TEXTURE); - if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit, *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ thread_scoped_lock device_lock(device_mutex); half *pixels = (half *)tex_img->alloc(1, 1); @@ -896,30 +778,36 @@ void ImageManager::device_load_image( thread_scoped_lock device_lock(device_mutex); tex_img->copy_to_device(); } + + /* Cleanup memory in image loader. */ + img->loader->cleanup(); img->need_load = false; } -void ImageManager::device_free_image(Device *, ImageDataType type, int slot) +void ImageManager::device_free_image(Device *, int slot) { - Image *img = images[type][slot]; + Image *img = images[slot]; + if (img == NULL) { + return; + } - if (img) { - if (osl_texture_system && !img->key.builtin_data) { + if (osl_texture_system) { #ifdef WITH_OSL - ustring filename(images[type][slot]->key.filename); - ((OSL::TextureSystem *)osl_texture_system)->invalidate(filename); -#endif - } - - if (img->mem) { - thread_scoped_lock device_lock(device_mutex); - delete img->mem; + ustring filepath = img->loader->osl_filepath(); + if (filepath) { + ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath); } +#endif + } - delete img; - images[type][slot] = NULL; - --tex_num_images[type]; + if (img->mem) { + thread_scoped_lock device_lock(device_mutex); + delete img->mem; } + + delete img->loader; + delete img; + images[slot] = NULL; } void ImageManager::device_update(Device *device, Scene *scene, Progress &progress) @@ -929,24 +817,14 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres } TaskPool pool; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) - continue; - - if (images[type][slot]->users == 0) { - device_free_image(device, (ImageDataType)type, slot); - } - else if (images[type][slot]->need_load) { - if (!osl_texture_system || images[type][slot]->key.builtin_data) - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->users == 0) { + device_free_image(device, slot); + } + else if (img && img->need_load) { + pool.push( + function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress)); } } @@ -955,23 +833,16 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres need_update = false; } -void ImageManager::device_update_slot(Device *device, - Scene *scene, - int flat_slot, - Progress *progress) +void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + Image *img = images[slot]; + assert(img != NULL); - Image *image = images[type][slot]; - assert(image != NULL); - - if (image->users == 0) { - device_free_image(device, type, slot); + if (img->users == 0) { + device_free_image(device, slot); } - else if (image->need_load) { - if (!osl_texture_system || image->key.builtin_data) - device_load_image(device, scene, type, slot, progress); + else if (img->need_load) { + device_load_image(device, scene, slot, progress); } } @@ -984,22 +855,11 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p } TaskPool pool; - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (!images[type][slot]) - continue; - - if (images[type][slot]->need_load) { - if (images[type][slot]->key.builtin_data) { - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } - } + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->need_load && img->builtin) { + pool.push( + function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress)); } } @@ -1008,31 +868,27 @@ void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &p void ImageManager::device_free_builtin(Device *device) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - if (images[type][slot] && images[type][slot]->key.builtin_data) - device_free_image(device, (ImageDataType)type, slot); + for (size_t slot = 0; slot < images.size(); slot++) { + Image *img = images[slot]; + if (img && img->builtin) { + device_free_image(device, slot); } } } void ImageManager::device_free(Device *device) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for (size_t slot = 0; slot < images[type].size(); slot++) { - device_free_image(device, (ImageDataType)type, slot); - } - images[type].clear(); + for (size_t slot = 0; slot < images.size(); slot++) { + device_free_image(device, slot); } + images.clear(); } void ImageManager::collect_statistics(RenderStats *stats) { - for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - foreach (const Image *image, images[type]) { - stats->image.textures.add_entry( - NamedSizeEntry(path_filename(image->key.filename), image->mem->memory_size())); - } + foreach (const Image *image, images) { + stats->image.textures.add_entry( + NamedSizeEntry(image->loader->name(), image->mem->memory_size())); } } |