Blender  V3.3
scene/image.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "scene/image.h"
5 #include "device/device.h"
6 #include "scene/colorspace.h"
7 #include "scene/image_oiio.h"
8 #include "scene/image_vdb.h"
9 #include "scene/scene.h"
10 #include "scene/stats.h"
11 
12 #include "util/foreach.h"
13 #include "util/image.h"
14 #include "util/image_impl.h"
15 #include "util/log.h"
16 #include "util/path.h"
17 #include "util/progress.h"
18 #include "util/task.h"
19 #include "util/texture.h"
20 #include "util/unique_ptr.h"
21 
22 #ifdef WITH_OSL
23 # include <OSL/oslexec.h>
24 #endif
25 
27 
28 namespace {
29 
30 /* Some helpers to silence warning in templated function. */
31 bool isfinite(uchar /*value*/)
32 {
33  return true;
34 }
35 bool isfinite(half /*value*/)
36 {
37  return true;
38 }
39 bool isfinite(uint16_t /*value*/)
40 {
41  return true;
42 }
43 
45 {
46  switch (type) {
48  return "float4";
50  return "byte4";
52  return "half4";
54  return "float";
56  return "byte";
58  return "half";
60  return "ushort4";
62  return "ushort";
64  return "nanovdb_float";
66  return "nanovdb_float3";
68  return "nanovdb_fpn";
70  return "nanovdb_fp16";
72  assert(!"System enumerator type, should never be used");
73  return "";
74  }
75  assert(!"Unhandled image data type");
76  return "";
77 }
78 
79 } // namespace
80 
81 /* Image Handle */
82 
84 {
85 }
86 
88  : tile_slots(other.tile_slots), manager(other.manager)
89 {
90  /* Increase image user count. */
91  foreach (const int slot, tile_slots) {
92  manager->add_image_user(slot);
93  }
94 }
95 
97 {
98  clear();
99  manager = other.manager;
100  tile_slots = other.tile_slots;
101 
102  foreach (const int slot, tile_slots) {
103  manager->add_image_user(slot);
104  }
105 
106  return *this;
107 }
108 
110 {
111  clear();
112 }
113 
115 {
116  foreach (const int slot, tile_slots) {
117  manager->remove_image_user(slot);
118  }
119 
120  tile_slots.clear();
121  manager = NULL;
122 }
123 
124 bool ImageHandle::empty() const
125 {
126  return tile_slots.empty();
127 }
128 
130 {
131  return tile_slots.size();
132 }
133 
135 {
136  if (tile_slots.empty()) {
137  return ImageMetaData();
138  }
139 
140  ImageManager::Image *img = manager->images[tile_slots.front()];
141  manager->load_image_metadata(img);
142  return img->metadata;
143 }
144 
145 int ImageHandle::svm_slot(const int tile_index) const
146 {
147  if (tile_index >= tile_slots.size()) {
148  return -1;
149  }
150 
151  if (manager->osl_texture_system) {
153  if (!img->loader->osl_filepath().empty()) {
154  return -1;
155  }
156  }
157 
158  return tile_slots[tile_index];
159 }
160 
162 {
163  const size_t num_nodes = divide_up(tile_slots.size(), 2);
164 
165  vector<int4> svm_slots;
166  svm_slots.reserve(num_nodes);
167  for (size_t i = 0; i < num_nodes; i++) {
168  int4 node;
169 
170  int slot = tile_slots[2 * i];
171  node.x = manager->images[slot]->loader->get_tile_number();
172  node.y = slot;
173 
174  if ((2 * i + 1) < tile_slots.size()) {
175  slot = tile_slots[2 * i + 1];
176  node.z = manager->images[slot]->loader->get_tile_number();
177  node.w = slot;
178  }
179  else {
180  node.z = -1;
181  node.w = -1;
182  }
183 
184  svm_slots.push_back(node);
185  }
186 
187  return svm_slots;
188 }
189 
191 {
192  if (tile_index >= tile_slots.size()) {
193  return NULL;
194  }
195 
197  return img ? img->mem : NULL;
198 }
199 
201 {
202  if (tile_index >= tile_slots.size()) {
203  return NULL;
204  }
205 
207 
208  if (img == NULL) {
209  return NULL;
210  }
211 
212  ImageLoader *loader = img->loader;
213 
214  if (loader == NULL) {
215  return NULL;
216  }
217 
218  if (loader->is_vdb_loader()) {
219  return dynamic_cast<VDBImageLoader *>(loader);
220  }
221 
222  return NULL;
223 }
224 
225 bool ImageHandle::operator==(const ImageHandle &other) const
226 {
227  return manager == other.manager && tile_slots == other.tile_slots;
228 }
229 
230 /* Image MetaData */
231 
233  : channels(0),
234  width(0),
235  height(0),
236  depth(0),
237  byte_size(0),
239  colorspace(u_colorspace_raw),
240  colorspace_file_format(""),
241  use_transform_3d(false),
242  compress_as_srgb(false)
243 {
244 }
245 
246 bool ImageMetaData::operator==(const ImageMetaData &other) const
247 {
248  return channels == other.channels && width == other.width && height == other.height &&
249  depth == other.depth && use_transform_3d == other.use_transform_3d &&
250  (!use_transform_3d || transform_3d == other.transform_3d) && type == other.type &&
252 }
253 
255 {
258 }
259 
261 {
262  /* Convert used specified color spaces to one we know how to handle. */
265 
266  if (colorspace == u_colorspace_raw) {
267  /* Nothing to do. */
268  }
269  else if (colorspace == u_colorspace_srgb) {
270  /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
271  * for the common case of 8bit sRGB images like PNG. */
272  compress_as_srgb = true;
273  }
274  else {
275  /* If colorspace conversion needed, use half instead of short so we can
276  * represent HDR values that might result from conversion. */
279  }
282  }
283  }
284 }
285 
286 /* Image Loader */
287 
289 {
290 }
291 
293 {
294  return ustring();
295 }
296 
298 {
299  return 0;
300 }
301 
303 {
304  if (a == NULL && b == NULL) {
305  return true;
306  }
307  else {
308  return (a && b && typeid(*a) == typeid(*b) && a->equals(*b));
309  }
310 }
311 
313 {
314  return false;
315 }
316 
317 /* Image Manager */
318 
320 {
321  need_update_ = true;
322  osl_texture_system = NULL;
323  animation_frame = 0;
324 
325  /* Set image limits */
326  features.has_nanovdb = info.has_nanovdb;
327 }
328 
330 {
331  for (size_t slot = 0; slot < images.size(); slot++)
332  assert(!images[slot]);
333 }
334 
335 void ImageManager::set_osl_texture_system(void *texture_system)
336 {
337  osl_texture_system = texture_system;
338 }
339 
341 {
342  if (frame != animation_frame) {
343  thread_scoped_lock device_lock(images_mutex);
344  animation_frame = frame;
345 
346  for (size_t slot = 0; slot < images.size(); slot++) {
347  if (images[slot] && images[slot]->params.animated)
348  return true;
349  }
350  }
351 
352  return false;
353 }
354 
355 void ImageManager::load_image_metadata(Image *img)
356 {
357  if (!img->need_metadata) {
358  return;
359  }
360 
361  thread_scoped_lock image_lock(img->mutex);
362  if (!img->need_metadata) {
363  return;
364  }
365 
366  ImageMetaData &metadata = img->metadata;
367  metadata = ImageMetaData();
368  metadata.colorspace = img->params.colorspace;
369 
370  if (img->loader->load_metadata(features, metadata)) {
371  assert(metadata.type != IMAGE_DATA_NUM_TYPES);
372  }
373  else {
374  metadata.type = IMAGE_DATA_TYPE_BYTE4;
375  }
376 
377  metadata.detect_colorspace();
378 
379  assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
380  metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
381  metadata.type != IMAGE_DATA_TYPE_NANOVDB_FPN ||
382  metadata.type != IMAGE_DATA_TYPE_NANOVDB_FP16));
383 
384  img->need_metadata = false;
385 }
386 
387 ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
388 {
389  const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
390 
391  ImageHandle handle;
392  handle.tile_slots.push_back(slot);
393  handle.manager = this;
394  return handle;
395 }
396 
397 ImageHandle ImageManager::add_image(const string &filename,
398  const ImageParams &params,
399  const array<int> &tiles)
400 {
401  ImageHandle handle;
402  handle.manager = this;
403 
404  foreach (int tile, tiles) {
405  string tile_filename = filename;
406 
407  /* Since we don't have information about the exact tile format used in this code location,
408  * just attempt all replacement patterns that Blender supports. */
409  if (tile != 0) {
410  string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
411 
412  int u = ((tile - 1001) % 10);
413  int v = ((tile - 1001) / 10);
414  string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
415  }
416  const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
417  handle.tile_slots.push_back(slot);
418  }
419 
420  return handle;
421 }
422 
424  const ImageParams &params,
425  const bool builtin)
426 {
427  const int slot = add_image_slot(loader, params, builtin);
428 
429  ImageHandle handle;
430  handle.tile_slots.push_back(slot);
431  handle.manager = this;
432  return handle;
433 }
434 
436  const ImageParams &params)
437 {
438  ImageHandle handle;
439  for (ImageLoader *loader : loaders) {
440  const int slot = add_image_slot(loader, params, true);
441  handle.tile_slots.push_back(slot);
442  }
443 
444  handle.manager = this;
445  return handle;
446 }
447 
448 int ImageManager::add_image_slot(ImageLoader *loader,
449  const ImageParams &params,
450  const bool builtin)
451 {
452  Image *img;
453  size_t slot;
454 
455  thread_scoped_lock device_lock(images_mutex);
456 
457  /* Find existing image. */
458  for (slot = 0; slot < images.size(); slot++) {
459  img = images[slot];
460  if (img && ImageLoader::equals(img->loader, loader) && img->params == params) {
461  img->users++;
462  delete loader;
463  return slot;
464  }
465  }
466 
467  /* Find free slot. */
468  for (slot = 0; slot < images.size(); slot++) {
469  if (!images[slot])
470  break;
471  }
472 
473  if (slot == images.size()) {
474  images.resize(images.size() + 1);
475  }
476 
477  /* Add new image. */
478  img = new Image();
479  img->params = params;
480  img->loader = loader;
481  img->need_metadata = true;
482  img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
483  img->builtin = builtin;
484  img->users = 1;
485  img->mem = NULL;
486 
487  images[slot] = img;
488 
489  need_update_ = true;
490 
491  return slot;
492 }
493 
494 void ImageManager::add_image_user(int slot)
495 {
496  thread_scoped_lock device_lock(images_mutex);
497  Image *image = images[slot];
498  assert(image && image->users >= 1);
499 
500  image->users++;
501 }
502 
503 void ImageManager::remove_image_user(int slot)
504 {
505  thread_scoped_lock device_lock(images_mutex);
506  Image *image = images[slot];
507  assert(image && image->users >= 1);
508 
509  /* decrement user count */
510  image->users--;
511 
512  /* don't remove immediately, rather do it all together later on. one of
513  * the reasons for this is that on shader changes we add and remove nodes
514  * that use them, but we do not want to reload the image all the time. */
515  if (image->users == 0)
516  need_update_ = true;
517 }
518 
520 {
521  /* For typical RGBA images we let OIIO convert to associated alpha,
522  * but some types we want to leave the RGB channels untouched. */
526 }
527 
528 template<TypeDesc::BASETYPE FileFormat, typename StorageType>
529 bool ImageManager::file_load_image(Image *img, int texture_limit)
530 {
531  /* Ignore empty images. */
532  if (!(img->metadata.channels > 0)) {
533  return false;
534  }
535 
536  /* Get metadata. */
537  int width = img->metadata.width;
538  int height = img->metadata.height;
539  int depth = img->metadata.depth;
540  int components = img->metadata.channels;
541 
542  /* Read pixels. */
543  vector<StorageType> pixels_storage;
544  StorageType *pixels;
545  const size_t max_size = max(max(width, height), depth);
546  if (max_size == 0) {
547  /* Don't bother with empty images. */
548  return false;
549  }
550 
551  /* Allocate memory as needed, may be smaller to resize down. */
552  if (texture_limit > 0 && max_size > texture_limit) {
553  pixels_storage.resize(((size_t)width) * height * depth * 4);
554  pixels = &pixels_storage[0];
555  }
556  else {
557  thread_scoped_lock device_lock(device_mutex);
558  pixels = (StorageType *)img->mem->alloc(width, height, depth);
559  }
560 
561  if (pixels == NULL) {
562  /* Could be that we've run out of memory. */
563  return false;
564  }
565 
566  const size_t num_pixels = ((size_t)width) * height * depth;
567  img->loader->load_pixels(
568  img->metadata, pixels, num_pixels * components, image_associate_alpha(img));
569 
570  /* The kernel can handle 1 and 4 channel images. Anything that is not a single
571  * channel image is converted to RGBA format. */
572  bool is_rgba = (img->metadata.type == IMAGE_DATA_TYPE_FLOAT4 ||
573  img->metadata.type == IMAGE_DATA_TYPE_HALF4 ||
574  img->metadata.type == IMAGE_DATA_TYPE_BYTE4 ||
575  img->metadata.type == IMAGE_DATA_TYPE_USHORT4);
576 
577  if (is_rgba) {
578  const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
579 
580  if (components == 2) {
581  /* Grayscale + alpha to RGBA. */
582  for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
583  pixels[i * 4 + 3] = pixels[i * 2 + 1];
584  pixels[i * 4 + 2] = pixels[i * 2 + 0];
585  pixels[i * 4 + 1] = pixels[i * 2 + 0];
586  pixels[i * 4 + 0] = pixels[i * 2 + 0];
587  }
588  }
589  else if (components == 3) {
590  /* RGB to RGBA. */
591  for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
592  pixels[i * 4 + 3] = one;
593  pixels[i * 4 + 2] = pixels[i * 3 + 2];
594  pixels[i * 4 + 1] = pixels[i * 3 + 1];
595  pixels[i * 4 + 0] = pixels[i * 3 + 0];
596  }
597  }
598  else if (components == 1) {
599  /* Grayscale to RGBA. */
600  for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
601  pixels[i * 4 + 3] = one;
602  pixels[i * 4 + 2] = pixels[i];
603  pixels[i * 4 + 1] = pixels[i];
604  pixels[i * 4 + 0] = pixels[i];
605  }
606  }
607 
608  /* Disable alpha if requested by the user. */
609  if (img->params.alpha_type == IMAGE_ALPHA_IGNORE) {
610  for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
611  pixels[i * 4 + 3] = one;
612  }
613  }
614  }
615 
616  if (img->metadata.colorspace != u_colorspace_raw &&
617  img->metadata.colorspace != u_colorspace_srgb) {
618  /* Convert to scene linear. */
620  img->metadata.colorspace, pixels, num_pixels, is_rgba, img->metadata.compress_as_srgb);
621  }
622 
623  /* Make sure we don't have buggy values. */
624  if (FileFormat == TypeDesc::FLOAT) {
625  /* For RGBA buffers we put all channels to 0 if either of them is not
626  * finite. This way we avoid possible artifacts caused by fully changed
627  * hue. */
628  if (is_rgba) {
629  for (size_t i = 0; i < num_pixels; i += 4) {
630  StorageType *pixel = &pixels[i * 4];
631  if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) ||
632  !isfinite(pixel[3])) {
633  pixel[0] = 0;
634  pixel[1] = 0;
635  pixel[2] = 0;
636  pixel[3] = 0;
637  }
638  }
639  }
640  else {
641  for (size_t i = 0; i < num_pixels; ++i) {
642  StorageType *pixel = &pixels[i];
643  if (!isfinite(pixel[0])) {
644  pixel[0] = 0;
645  }
646  }
647  }
648  }
649 
650  /* Scale image down if needed. */
651  if (pixels_storage.size() > 0) {
652  float scale_factor = 1.0f;
653  while (max_size * scale_factor > texture_limit) {
654  scale_factor *= 0.5f;
655  }
656  VLOG_WORK << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
657  << ".";
658  vector<StorageType> scaled_pixels;
659  size_t scaled_width, scaled_height, scaled_depth;
660  util_image_resize_pixels(pixels_storage,
661  width,
662  height,
663  depth,
664  is_rgba ? 4 : 1,
665  scale_factor,
666  &scaled_pixels,
667  &scaled_width,
668  &scaled_height,
669  &scaled_depth);
670 
671  StorageType *texture_pixels;
672 
673  {
674  thread_scoped_lock device_lock(device_mutex);
675  texture_pixels = (StorageType *)img->mem->alloc(scaled_width, scaled_height, scaled_depth);
676  }
677 
678  memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType));
679  }
680 
681  return true;
682 }
683 
684 void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
685 {
686  if (progress->get_cancel()) {
687  return;
688  }
689 
690  Image *img = images[slot];
691 
692  progress->set_status("Updating Images", "Loading " + img->loader->name());
693 
694  const int texture_limit = scene->params.texture_limit;
695 
696  load_image_metadata(img);
697  ImageDataType type = img->metadata.type;
698 
699  /* Name for debugging. */
700  img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), slot);
701 
702  /* Free previous texture in slot. */
703  if (img->mem) {
704  thread_scoped_lock device_lock(device_mutex);
705  delete img->mem;
706  img->mem = NULL;
707  }
708 
709  img->mem = new device_texture(
710  device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
711  img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
712  img->mem->info.transform_3d = img->metadata.transform_3d;
713 
714  /* Create new texture. */
715  if (type == IMAGE_DATA_TYPE_FLOAT4) {
716  if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
717  /* on failure to load, we set a 1x1 pixels pink image */
718  thread_scoped_lock device_lock(device_mutex);
719  float *pixels = (float *)img->mem->alloc(1, 1);
720 
721  pixels[0] = TEX_IMAGE_MISSING_R;
722  pixels[1] = TEX_IMAGE_MISSING_G;
723  pixels[2] = TEX_IMAGE_MISSING_B;
724  pixels[3] = TEX_IMAGE_MISSING_A;
725  }
726  }
727  else if (type == IMAGE_DATA_TYPE_FLOAT) {
728  if (!file_load_image<TypeDesc::FLOAT, float>(img, texture_limit)) {
729  /* on failure to load, we set a 1x1 pixels pink image */
730  thread_scoped_lock device_lock(device_mutex);
731  float *pixels = (float *)img->mem->alloc(1, 1);
732 
733  pixels[0] = TEX_IMAGE_MISSING_R;
734  }
735  }
736  else if (type == IMAGE_DATA_TYPE_BYTE4) {
737  if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
738  /* on failure to load, we set a 1x1 pixels pink image */
739  thread_scoped_lock device_lock(device_mutex);
740  uchar *pixels = (uchar *)img->mem->alloc(1, 1);
741 
742  pixels[0] = (TEX_IMAGE_MISSING_R * 255);
743  pixels[1] = (TEX_IMAGE_MISSING_G * 255);
744  pixels[2] = (TEX_IMAGE_MISSING_B * 255);
745  pixels[3] = (TEX_IMAGE_MISSING_A * 255);
746  }
747  }
748  else if (type == IMAGE_DATA_TYPE_BYTE) {
749  if (!file_load_image<TypeDesc::UINT8, uchar>(img, texture_limit)) {
750  /* on failure to load, we set a 1x1 pixels pink image */
751  thread_scoped_lock device_lock(device_mutex);
752  uchar *pixels = (uchar *)img->mem->alloc(1, 1);
753 
754  pixels[0] = (TEX_IMAGE_MISSING_R * 255);
755  }
756  }
757  else if (type == IMAGE_DATA_TYPE_HALF4) {
758  if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
759  /* on failure to load, we set a 1x1 pixels pink image */
760  thread_scoped_lock device_lock(device_mutex);
761  half *pixels = (half *)img->mem->alloc(1, 1);
762 
763  pixels[0] = TEX_IMAGE_MISSING_R;
764  pixels[1] = TEX_IMAGE_MISSING_G;
765  pixels[2] = TEX_IMAGE_MISSING_B;
766  pixels[3] = TEX_IMAGE_MISSING_A;
767  }
768  }
769  else if (type == IMAGE_DATA_TYPE_USHORT) {
770  if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
771  /* on failure to load, we set a 1x1 pixels pink image */
772  thread_scoped_lock device_lock(device_mutex);
773  uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
774 
775  pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
776  }
777  }
778  else if (type == IMAGE_DATA_TYPE_USHORT4) {
779  if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, texture_limit)) {
780  /* on failure to load, we set a 1x1 pixels pink image */
781  thread_scoped_lock device_lock(device_mutex);
782  uint16_t *pixels = (uint16_t *)img->mem->alloc(1, 1);
783 
784  pixels[0] = (TEX_IMAGE_MISSING_R * 65535);
785  pixels[1] = (TEX_IMAGE_MISSING_G * 65535);
786  pixels[2] = (TEX_IMAGE_MISSING_B * 65535);
787  pixels[3] = (TEX_IMAGE_MISSING_A * 65535);
788  }
789  }
790  else if (type == IMAGE_DATA_TYPE_HALF) {
791  if (!file_load_image<TypeDesc::HALF, half>(img, texture_limit)) {
792  /* on failure to load, we set a 1x1 pixels pink image */
793  thread_scoped_lock device_lock(device_mutex);
794  half *pixels = (half *)img->mem->alloc(1, 1);
795 
796  pixels[0] = TEX_IMAGE_MISSING_R;
797  }
798  }
799 #ifdef WITH_NANOVDB
802  thread_scoped_lock device_lock(device_mutex);
803  void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
804 
805  if (pixels != NULL) {
806  img->loader->load_pixels(img->metadata, pixels, img->metadata.byte_size, false);
807  }
808  }
809 #endif
810 
811  {
812  thread_scoped_lock device_lock(device_mutex);
813  img->mem->copy_to_device();
814  }
815 
816  /* Cleanup memory in image loader. */
817  img->loader->cleanup();
818  img->need_load = false;
819 }
820 
821 void ImageManager::device_free_image(Device *, int slot)
822 {
823  Image *img = images[slot];
824  if (img == NULL) {
825  return;
826  }
827 
828  if (osl_texture_system) {
829 #ifdef WITH_OSL
830  ustring filepath = img->loader->osl_filepath();
831  if (!filepath.empty()) {
832  ((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
833  }
834 #endif
835  }
836 
837  if (img->mem) {
838  thread_scoped_lock device_lock(device_mutex);
839  delete img->mem;
840  }
841 
842  delete img->loader;
843  delete img;
844  images[slot] = NULL;
845 }
846 
848 {
849  if (!need_update()) {
850  return;
851  }
852 
853  scoped_callback_timer timer([scene](double time) {
854  if (scene->update_stats) {
855  scene->update_stats->image.times.add_entry({"device_update", time});
856  }
857  });
858 
859  TaskPool pool;
860  for (size_t slot = 0; slot < images.size(); slot++) {
861  Image *img = images[slot];
862  if (img && img->users == 0) {
863  device_free_image(device, slot);
864  }
865  else if (img && img->need_load) {
866  pool.push(
867  function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
868  }
869  }
870 
871  pool.wait_work();
872 
873  need_update_ = false;
874 }
875 
876 void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
877 {
878  Image *img = images[slot];
879  assert(img != NULL);
880 
881  if (img->users == 0) {
882  device_free_image(device, slot);
883  }
884  else if (img->need_load) {
885  device_load_image(device, scene, slot, progress);
886  }
887 }
888 
890 {
891  /* Load only builtin images, Blender needs this to load evaluated
892  * scene data from depsgraph before it is freed. */
893  if (!need_update()) {
894  return;
895  }
896 
897  TaskPool pool;
898  for (size_t slot = 0; slot < images.size(); slot++) {
899  Image *img = images[slot];
900  if (img && img->need_load && img->builtin) {
901  pool.push(
902  function_bind(&ImageManager::device_load_image, this, device, scene, slot, &progress));
903  }
904  }
905 
906  pool.wait_work();
907 }
908 
910 {
911  for (size_t slot = 0; slot < images.size(); slot++) {
912  Image *img = images[slot];
913  if (img && img->builtin) {
914  device_free_image(device, slot);
915  }
916  }
917 }
918 
920 {
921  for (size_t slot = 0; slot < images.size(); slot++) {
922  device_free_image(device, slot);
923  }
924  images.clear();
925 }
926 
928 {
929  foreach (const Image *image, images) {
930  if (!image) {
931  /* Image may have been freed due to lack of users. */
932  continue;
933  }
934  stats->image.textures.add_entry(
935  NamedSizeEntry(image->loader->name(), image->mem->memory_size()));
936  }
937 }
938 
940 {
941  need_update_ = true;
942 }
943 
945 {
946  return need_update_;
947 }
948 
unsigned char uchar
Definition: BLI_sys_types.h:70
struct Image Image
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
ATTR_WARN_UNUSED_RESULT const BMVert * v
static bool colorspace_is_data(ustring colorspace)
Definition: colorspace.cpp:72
static void to_scene_linear(ustring colorspace, T *pixels, size_t num_pixels, bool is_rgba, bool compress_as_srgb)
Definition: colorspace.cpp:350
static ustring detect_known_colorspace(ustring colorspace, const char *file_format, bool is_float)
Definition: colorspace.cpp:97
bool has_nanovdb
Definition: device/device.h:67
int num_tiles() const
bool operator==(const ImageHandle &other) const
vector< int > tile_slots
VDBImageLoader * vdb_loader(const int tile_index=0) const
device_texture * image_memory(const int tile_index=0) const
bool empty() const
ImageManager * manager
ImageHandle & operator=(const ImageHandle &other)
Definition: scene/image.cpp:96
ImageMetaData metadata()
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)
void tag_update()
ImageManager(const DeviceInfo &info)
void device_update(Device *device, Scene *scene, Progress &progress)
bool need_update() const
void device_free(Device *device)
void device_load_builtin(Device *device, Scene *scene, Progress &progress)
void device_free_builtin(Device *device)
ImageHandle add_image(const string &filename, const ImageParams &params)
void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
void collect_statistics(RenderStats *stats)
void set_osl_texture_system(void *texture_system)
ImageDataType type
bool is_float() const
Transform transform_3d
void detect_colorspace()
bool operator==(const ImageMetaData &other) const
const char * colorspace_file_format
ImageAlphaType alpha_type
NamedSizeStats textures
Definition: scene/stats.h:160
short type
uint height() const
Definition: Image.cpp:49
uint width() const
Definition: Image.cpp:44
void add_entry(const NamedSizeEntry &entry)
Definition: stats.cpp:65
bool get_cancel() const
Definition: progress.h:90
void set_status(const string &status_, const string &substatus_="")
Definition: progress.h:248
int texture_limit
Definition: scene.h:155
Definition: half.h:41
ustring u_colorspace_raw
ustring u_colorspace_srgb
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
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)
OperationNode * node
double time
Scene scene
#define function_bind
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
const int tile_index
ccl_gpu_kernel_postfix ccl_global float int num_pixels
ccl_global const KernelWorkTile * tile
#define VLOG_WORK
Definition: log.h:80
bool isfinite(uint16_t)
Definition: scene/image.cpp:39
const char * name_from_type(ImageDataType type)
Definition: scene/image.cpp:44
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
@ FLOAT
static bool image_associate_alpha(ImageManager::Image *img)
unsigned short uint16_t
Definition: stdint.h:79
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: string.cpp:22
void string_replace(string &haystack, const string &needle, const string &other)
Definition: string.cpp:130
device_texture * mem
ImageStats image
Definition: scene/stats.h:177
SceneParams params
Definition: scene.h:243
SceneUpdateStats * update_stats
Definition: scene.h:249
void push(TaskRunFunction &&task)
Definition: task.cpp:23
void wait_work(Summary *stats=NULL)
Definition: task.cpp:29
std::unique_lock< std::mutex > thread_scoped_lock
Definition: thread.h:28
float max
ImageDataType
Definition: util/texture.h:29
@ IMAGE_DATA_NUM_TYPES
Definition: util/texture.h:43
@ IMAGE_DATA_TYPE_BYTE
Definition: util/texture.h:34
@ IMAGE_DATA_TYPE_FLOAT
Definition: util/texture.h:33
@ IMAGE_DATA_TYPE_NANOVDB_FP16
Definition: util/texture.h:41
@ IMAGE_DATA_TYPE_FLOAT4
Definition: util/texture.h:30
@ IMAGE_DATA_TYPE_USHORT4
Definition: util/texture.h:36
@ IMAGE_DATA_TYPE_USHORT
Definition: util/texture.h:37
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
Definition: util/texture.h:38
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
Definition: util/texture.h:39
@ IMAGE_DATA_TYPE_HALF
Definition: util/texture.h:35
@ IMAGE_DATA_TYPE_BYTE4
Definition: util/texture.h:31
@ IMAGE_DATA_TYPE_HALF4
Definition: util/texture.h:32
@ IMAGE_DATA_TYPE_NANOVDB_FPN
Definition: util/texture.h:40
@ IMAGE_ALPHA_CHANNEL_PACKED
Definition: util/texture.h:51
@ IMAGE_ALPHA_IGNORE
Definition: util/texture.h:52
#define TEX_IMAGE_MISSING_R
Definition: util/texture.h:12
#define TEX_IMAGE_MISSING_B
Definition: util/texture.h:14
#define TEX_IMAGE_MISSING_A
Definition: util/texture.h:15
#define TEX_IMAGE_MISSING_G
Definition: util/texture.h:13
ccl_device_inline size_t divide_up(size_t x, size_t y)
Definition: util/types.h:51