Blender  V2.93
colormanagement.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 by Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "IMB_colormanagement.h"
26 
27 #include <math.h>
28 #include <string.h>
29 
30 #include "DNA_color_types.h"
31 #include "DNA_image_types.h"
32 #include "DNA_movieclip_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_space_types.h"
35 
36 #include "IMB_filetype.h"
37 #include "IMB_filter.h"
38 #include "IMB_imbuf.h"
39 #include "IMB_imbuf_types.h"
40 #include "IMB_metadata.h"
41 #include "IMB_moviecache.h"
42 
43 #include "MEM_guardedalloc.h"
44 
45 #include "BLI_blenlib.h"
46 #include "BLI_math.h"
47 #include "BLI_math_color.h"
48 #include "BLI_rect.h"
49 #include "BLI_string.h"
50 #include "BLI_threads.h"
51 
52 #include "BKE_appdir.h"
53 #include "BKE_colortools.h"
54 #include "BKE_context.h"
55 #include "BKE_image.h"
56 #include "BKE_main.h"
57 
58 #include "RNA_define.h"
59 
60 #include "SEQ_iterator.h"
61 
62 #include <ocio_capi.h>
63 
64 /* -------------------------------------------------------------------- */
68 #define DISPLAY_BUFFER_CHANNELS 4
69 
70 /* ** list of all supported color spaces, displays and views */
78 
83 
84 static int global_tot_colorspace = 0;
85 static int global_tot_display = 0;
86 static int global_tot_view = 0;
87 static int global_tot_looks = 0;
88 
89 /* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
90 float imbuf_luma_coefficients[3] = {0.0f};
91 float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
92 float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
93 static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
94 static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
95 
96 /* lock used by pre-cached processors getters, so processor wouldn't
97  * be created several times
98  * LOCK_COLORMANAGE can not be used since this mutex could be needed to
99  * be locked before pre-cached processor are creating
100  */
101 static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER;
102 
103 typedef struct ColormanageProcessor {
104  OCIO_ConstCPUProcessorRcPtr *cpu_processor;
108 
109 static struct global_gpu_state {
110  /* GPU shader currently bound. */
112 
113  /* Curve mapping. */
118 } global_gpu_state = {false};
119 
121  /* Cached processor for color picking conversion. */
122  OCIO_ConstCPUProcessorRcPtr *cpu_processor_to;
123  OCIO_ConstCPUProcessorRcPtr *cpu_processor_from;
124  bool failed;
126 
129 /* -------------------------------------------------------------------- */
189 /* NOTE: ColormanageCacheViewSettings and ColormanageCacheDisplaySettings are
190  * quite the same as ColorManagedViewSettings and ColorManageDisplaySettings
191  * but they holds indexes of all transformations and color spaces, not
192  * their names.
193  *
194  * This helps avoid extra colorspace / display / view lookup without
195  * requiring to pass all variables which affects on display buffer
196  * to color management cache system and keeps calls small and nice.
197  */
199  int flag;
200  int look;
201  int view;
202  float exposure;
203  float gamma;
204  float dither;
207 
209  int display;
211 
212 typedef struct ColormanageCacheKey {
213  int view; /* view transformation used for display buffer */
214  int display; /* display device name */
216 
217 typedef struct ColormanageCacheData {
218  int flag; /* view flags of cached buffer */
219  int look; /* Additional artistics transform */
220  float exposure; /* exposure value cached buffer is calculated with */
221  float gamma; /* gamma value cached buffer is calculated with */
222  float dither; /* dither value cached buffer is calculated with */
223  CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
224  int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
226 
227 typedef struct ColormanageCache {
229 
232 
233 static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
234 {
235  if (!ibuf->colormanage_cache) {
236  return NULL;
237  }
238 
239  return ibuf->colormanage_cache->moviecache;
240 }
241 
243 {
244  if (!ibuf->colormanage_cache) {
245  return NULL;
246  }
247 
248  return ibuf->colormanage_cache->data;
249 }
250 
251 static unsigned int colormanage_hashhash(const void *key_v)
252 {
253  const ColormanageCacheKey *key = key_v;
254 
255  unsigned int rval = (key->display << 16) | (key->view % 0xffff);
256 
257  return rval;
258 }
259 
260 static bool colormanage_hashcmp(const void *av, const void *bv)
261 {
262  const ColormanageCacheKey *a = av;
263  const ColormanageCacheKey *b = bv;
264 
265  return ((a->view != b->view) || (a->display != b->display));
266 }
267 
269 {
270  if (!ibuf->colormanage_cache) {
271  ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
272  }
273 
274  if (!ibuf->colormanage_cache->moviecache) {
275  struct MovieCache *moviecache;
276 
277  moviecache = IMB_moviecache_create("colormanage cache",
278  sizeof(ColormanageCacheKey),
281 
282  ibuf->colormanage_cache->moviecache = moviecache;
283  }
284 
285  return ibuf->colormanage_cache->moviecache;
286 }
287 
289 {
290  if (!ibuf->colormanage_cache) {
291  ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
292  }
293 
294  ibuf->colormanage_cache->data = data;
295 }
296 
298  ColormanageCacheViewSettings *cache_view_settings,
299  const ColorManagedViewSettings *view_settings)
300 {
301  int look = IMB_colormanagement_look_get_named_index(view_settings->look);
303 
304  cache_view_settings->look = look;
305  cache_view_settings->view = view;
306  cache_view_settings->exposure = view_settings->exposure;
307  cache_view_settings->gamma = view_settings->gamma;
308  cache_view_settings->dither = ibuf->dither;
309  cache_view_settings->flag = view_settings->flag;
310  cache_view_settings->curve_mapping = view_settings->curve_mapping;
311 }
312 
314  ColormanageCacheDisplaySettings *cache_display_settings,
315  const ColorManagedDisplaySettings *display_settings)
316 {
317  int display = IMB_colormanagement_display_get_named_index(display_settings->display_device);
318 
319  cache_display_settings->display = display;
320 }
321 
323  const ColormanageCacheViewSettings *view_settings,
324  const ColormanageCacheDisplaySettings *display_settings)
325 {
326  key->view = view_settings->view;
327  key->display = display_settings->display;
328 }
329 
331  ColormanageCacheKey *key,
332  void **cache_handle)
333 {
334  ImBuf *cache_ibuf;
335  struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
336 
337  if (!moviecache) {
338  /* If there's no moviecache it means no color management was applied
339  * on given image buffer before. */
340  return NULL;
341  }
342 
343  *cache_handle = NULL;
344 
345  cache_ibuf = IMB_moviecache_get(moviecache, key);
346 
347  *cache_handle = cache_ibuf;
348 
349  return cache_ibuf;
350 }
351 
352 static unsigned char *colormanage_cache_get(
353  ImBuf *ibuf,
354  const ColormanageCacheViewSettings *view_settings,
355  const ColormanageCacheDisplaySettings *display_settings,
356  void **cache_handle)
357 {
359  ImBuf *cache_ibuf;
360  int view_flag = 1 << (view_settings->view - 1);
361  CurveMapping *curve_mapping = view_settings->curve_mapping;
362  int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
363 
364  colormanage_settings_to_key(&key, view_settings, display_settings);
365 
366  /* check whether image was marked as dirty for requested transform */
367  if ((ibuf->display_buffer_flags[display_settings->display - 1] & view_flag) == 0) {
368  return NULL;
369  }
370 
371  cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
372 
373  if (cache_ibuf) {
374  ColormanageCacheData *cache_data;
375 
376  BLI_assert(cache_ibuf->x == ibuf->x && cache_ibuf->y == ibuf->y);
377 
378  /* only buffers with different color space conversions are being stored
379  * in cache separately. buffer which were used only different exposure/gamma
380  * are re-suing the same cached buffer
381  *
382  * check here which exposure/gamma/curve was used for cached buffer and if they're
383  * different from requested buffer should be re-generated
384  */
385  cache_data = colormanage_cachedata_get(cache_ibuf);
386 
387  if (cache_data->look != view_settings->look ||
388  cache_data->exposure != view_settings->exposure ||
389  cache_data->gamma != view_settings->gamma || cache_data->dither != view_settings->dither ||
390  cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping ||
391  cache_data->curve_mapping_timestamp != curve_mapping_timestamp) {
392  *cache_handle = NULL;
393 
394  IMB_freeImBuf(cache_ibuf);
395 
396  return NULL;
397  }
398 
399  return (unsigned char *)cache_ibuf->rect;
400  }
401 
402  return NULL;
403 }
404 
405 static void colormanage_cache_put(ImBuf *ibuf,
406  const ColormanageCacheViewSettings *view_settings,
407  const ColormanageCacheDisplaySettings *display_settings,
408  unsigned char *display_buffer,
409  void **cache_handle)
410 {
412  ImBuf *cache_ibuf;
413  ColormanageCacheData *cache_data;
414  int view_flag = 1 << (view_settings->view - 1);
415  struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
416  CurveMapping *curve_mapping = view_settings->curve_mapping;
417  int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
418 
419  colormanage_settings_to_key(&key, view_settings, display_settings);
420 
421  /* mark display buffer as valid */
422  ibuf->display_buffer_flags[display_settings->display - 1] |= view_flag;
423 
424  /* buffer itself */
425  cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
426  cache_ibuf->rect = (unsigned int *)display_buffer;
427 
428  cache_ibuf->mall |= IB_rect;
429  cache_ibuf->flags |= IB_rect;
430 
431  /* Store data which is needed to check whether cached buffer
432  * could be used for color managed display settings. */
433  cache_data = MEM_callocN(sizeof(ColormanageCacheData), "color manage cache imbuf data");
434  cache_data->look = view_settings->look;
435  cache_data->exposure = view_settings->exposure;
436  cache_data->gamma = view_settings->gamma;
437  cache_data->dither = view_settings->dither;
438  cache_data->flag = view_settings->flag;
439  cache_data->curve_mapping = curve_mapping;
440  cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
441 
442  colormanage_cachedata_set(cache_ibuf, cache_data);
443 
444  *cache_handle = cache_ibuf;
445 
446  IMB_moviecache_put(moviecache, &key, cache_ibuf);
447 }
448 
449 static void colormanage_cache_handle_release(void *cache_handle)
450 {
451  ImBuf *cache_ibuf = cache_handle;
452 
453  IMB_freeImBuf(cache_ibuf);
454 }
455 
458 /* -------------------------------------------------------------------- */
462 static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
463  char *colorspace_name,
464  const char *role,
465  const char *backup_role)
466 {
467  OCIO_ConstColorSpaceRcPtr *ociocs;
468 
469  ociocs = OCIO_configGetColorSpace(config, role);
470 
471  if (!ociocs && backup_role) {
472  ociocs = OCIO_configGetColorSpace(config, backup_role);
473  }
474 
475  if (ociocs) {
476  const char *name = OCIO_colorSpaceGetName(ociocs);
477 
478  /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
479  BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
480  OCIO_colorSpaceRelease(ociocs);
481  }
482  else {
483  printf("Color management: Error could not find role %s role.\n", role);
484  }
485 }
486 
487 static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
488 {
489  int tot_colorspace, tot_display, tot_display_view, tot_looks;
490  int index, viewindex, viewindex2;
491  const char *name;
492 
493  /* get roles */
507 
508  /* load colorspaces */
509  tot_colorspace = OCIO_configGetNumColorSpaces(config);
510  for (index = 0; index < tot_colorspace; index++) {
511  OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
512  const char *description;
513  bool is_invertible, is_data;
514 
515  name = OCIO_configGetColorSpaceNameByIndex(config, index);
516 
517  ocio_colorspace = OCIO_configGetColorSpace(config, name);
518  description = OCIO_colorSpaceGetDescription(ocio_colorspace);
519  is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
520  is_data = OCIO_colorSpaceIsData(ocio_colorspace);
521 
522  colormanage_colorspace_add(name, description, is_invertible, is_data);
523 
524  OCIO_colorSpaceRelease(ocio_colorspace);
525  }
526 
527  /* load displays */
528  viewindex2 = 0;
529  tot_display = OCIO_configGetNumDisplays(config);
530 
531  for (index = 0; index < tot_display; index++) {
532  const char *displayname;
533  ColorManagedDisplay *display;
534 
535  displayname = OCIO_configGetDisplay(config, index);
536 
537  display = colormanage_display_add(displayname);
538 
539  /* load views */
540  tot_display_view = OCIO_configGetNumViews(config, displayname);
541  for (viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
542  const char *viewname;
544  LinkData *display_view;
545 
546  viewname = OCIO_configGetView(config, displayname, viewindex);
547 
548  /* first check if view transform with given name was already loaded */
549  view = colormanage_view_get_named(viewname);
550 
551  if (!view) {
552  view = colormanage_view_add(viewname);
553  }
554 
555  display_view = BLI_genericNodeN(view);
556 
557  BLI_addtail(&display->views, display_view);
558  }
559  }
560 
561  global_tot_display = tot_display;
562 
563  /* load looks */
564  tot_looks = OCIO_configGetNumLooks(config);
565  colormanage_look_add("None", "", true);
566  for (index = 0; index < tot_looks; index++) {
567  OCIO_ConstLookRcPtr *ocio_look;
568  const char *process_space;
569 
570  name = OCIO_configGetLookNameByIndex(config, index);
571  ocio_look = OCIO_configGetLook(config, name);
572  process_space = OCIO_lookGetProcessSpace(ocio_look);
573  OCIO_lookRelease(ocio_look);
574 
575  colormanage_look_add(name, process_space, false);
576  }
577 
578  /* Load luminance coefficients. */
584 }
585 
586 static void colormanage_free_config(void)
587 {
588  ColorSpace *colorspace;
589  ColorManagedDisplay *display;
590 
591  /* free color spaces */
592  colorspace = global_colorspaces.first;
593  while (colorspace) {
594  ColorSpace *colorspace_next = colorspace->next;
595 
596  /* free precomputer processors */
597  if (colorspace->to_scene_linear) {
598  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
599  }
600  if (colorspace->from_scene_linear) {
601  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->from_scene_linear);
602  }
603 
604  /* free color space itself */
605  MEM_freeN(colorspace);
606 
607  colorspace = colorspace_next;
608  }
611 
612  /* free displays */
613  display = global_displays.first;
614  while (display) {
615  ColorManagedDisplay *display_next = display->next;
616 
617  /* free precomputer processors */
618  if (display->to_scene_linear) {
619  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear);
620  }
621  if (display->from_scene_linear) {
622  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear);
623  }
624 
625  /* free list of views */
626  BLI_freelistN(&display->views);
627 
628  MEM_freeN(display);
629  display = display_next;
630  }
632  global_tot_display = 0;
633 
634  /* free views */
636  global_tot_view = 0;
637 
638  /* free looks */
640  global_tot_looks = 0;
641 
642  OCIO_exit();
643 }
644 
646 {
647  const char *ocio_env;
648  const char *configdir;
649  char configfile[FILE_MAX];
650  OCIO_ConstConfigRcPtr *config = NULL;
651 
652  OCIO_init();
653 
654  ocio_env = BLI_getenv("OCIO");
655 
656  if (ocio_env && ocio_env[0] != '\0') {
657  config = OCIO_configCreateFromEnv();
658  if (config != NULL) {
659  printf("Color management: Using %s as a configuration file\n", ocio_env);
660  }
661  }
662 
663  if (config == NULL) {
664  configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement");
665 
666  if (configdir) {
667  BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
668 
669 #ifdef WIN32
670  {
671  /* quite a hack to support loading configuration from path with non-acii symbols */
672 
673  char short_name[256];
674  BLI_get_short_name(short_name, configfile);
675  config = OCIO_configCreateFromFile(short_name);
676  }
677 #else
678  config = OCIO_configCreateFromFile(configfile);
679 #endif
680  }
681  }
682 
683  if (config == NULL) {
684  printf("Color management: using fallback mode for management\n");
685 
686  config = OCIO_configCreateFallback();
687  }
688 
689  if (config) {
690  OCIO_setCurrentConfig(config);
691 
692  colormanage_load_config(config);
693 
694  OCIO_configRelease(config);
695  }
696 
697  /* If there are no valid display/views, use fallback mode. */
698  if (global_tot_display == 0 || global_tot_view == 0) {
699  printf("Color management: no displays/views in the config, using fallback mode instead\n");
700 
701  /* Free old config. */
703 
704  /* Initialize fallback config. */
705  config = OCIO_configCreateFallback();
706  colormanage_load_config(config);
707  }
708 
710 }
711 
713 {
715 
718  }
719 
722  }
723 
726  }
727 
730  }
731 
732  memset(&global_gpu_state, 0, sizeof(global_gpu_state));
734 
736 }
737 
740 /* -------------------------------------------------------------------- */
744 static bool colormanage_compatible_look(ColorManagedLook *look, const char *view_name)
745 {
746  if (look->is_noop) {
747  return true;
748  }
749 
750  /* Skip looks only relevant to specific view transforms. */
751  return (look->view[0] == 0 || (view_name && STREQ(look->view, view_name)));
752 }
753 
754 static bool colormanage_use_look(const char *look, const char *view_name)
755 {
756  ColorManagedLook *look_descr = colormanage_look_get_named(look);
757  return (look_descr->is_noop == false && colormanage_compatible_look(look_descr, view_name));
758 }
759 
761 {
762  if (ibuf->display_buffer_flags) {
764 
765  ibuf->display_buffer_flags = NULL;
766  }
767 
768  if (ibuf->colormanage_cache) {
770  struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
771 
772  if (cache_data) {
773  MEM_freeN(cache_data);
774  }
775 
776  if (moviecache) {
777  IMB_moviecache_free(moviecache);
778  }
779 
781 
782  ibuf->colormanage_cache = NULL;
783  }
784 }
785 
787  const bContext *C,
788  ColorManagedViewSettings **r_view_settings,
789  ColorManagedDisplaySettings **r_display_settings)
790 {
793 
794  *r_view_settings = &scene->view_settings;
795  *r_display_settings = &scene->display_settings;
796 
797  if (sima && sima->image) {
798  if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0) {
799  *r_view_settings = NULL;
800  }
801  }
802 }
803 
805  const ColorManagedViewSettings *view_settings,
806  const ColorManagedDisplaySettings *display_settings)
807 {
808  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
809 
810  const char *display = display_settings->display_device;
811  const char *view = view_settings->view_transform;
812  const char *colorspace_name;
813 
814  colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view);
815 
816  OCIO_configRelease(config);
817 
818  return colorspace_name;
819 }
820 
822  const ColorManagedViewSettings *view_settings,
823  const ColorManagedDisplaySettings *display_settings)
824 {
825  const char *colorspace_name = IMB_colormanagement_get_display_colorspace_name(view_settings,
826  display_settings);
827 
828  if (colorspace_name) {
829  return colormanage_colorspace_get_named(colorspace_name);
830  }
831 
832  return NULL;
833 }
834 
835 static OCIO_ConstCPUProcessorRcPtr *create_display_buffer_processor(const char *look,
836  const char *view_transform,
837  const char *display,
838  float exposure,
839  float gamma,
840  const char *from_colorspace)
841 {
842  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
843  const bool use_look = colormanage_use_look(look, view_transform);
844  const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
845  const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
846 
847  OCIO_ConstProcessorRcPtr *processor = OCIO_createDisplayProcessor(
848  config, from_colorspace, view_transform, display, (use_look) ? look : "", scale, exponent);
849 
850  OCIO_configRelease(config);
851 
852  if (processor == NULL) {
853  return NULL;
854  }
855 
856  OCIO_ConstCPUProcessorRcPtr *cpu_processor = OCIO_processorGetCPUProcessor(processor);
857  OCIO_processorRelease(processor);
858 
859  return cpu_processor;
860 }
861 
862 static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
863  const char *to_colorspace)
864 {
865  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
866  OCIO_ConstProcessorRcPtr *processor;
867 
868  processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
869 
870  OCIO_configRelease(config);
871 
872  return processor;
873 }
874 
875 static OCIO_ConstCPUProcessorRcPtr *colorspace_to_scene_linear_cpu_processor(
876  ColorSpace *colorspace)
877 {
878  if (colorspace->to_scene_linear == NULL) {
880 
881  if (colorspace->to_scene_linear == NULL) {
882  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
883  colorspace->name, global_role_scene_linear);
884 
885  if (processor != NULL) {
886  colorspace->to_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
888  OCIO_processorRelease(processor);
889  }
890  }
891 
893  }
894 
895  return (OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear;
896 }
897 
898 static OCIO_ConstCPUProcessorRcPtr *colorspace_from_scene_linear_cpu_processor(
899  ColorSpace *colorspace)
900 {
901  if (colorspace->from_scene_linear == NULL) {
903 
904  if (colorspace->from_scene_linear == NULL) {
905  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
906  global_role_scene_linear, colorspace->name);
907 
908  if (processor != NULL) {
909  colorspace->from_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
911  OCIO_processorRelease(processor);
912  }
913  }
914 
916  }
917 
918  return (OCIO_ConstCPUProcessorRcPtr *)colorspace->from_scene_linear;
919 }
920 
921 static OCIO_ConstCPUProcessorRcPtr *display_from_scene_linear_processor(
922  ColorManagedDisplay *display)
923 {
924  if (display->from_scene_linear == NULL) {
926 
927  if (display->from_scene_linear == NULL) {
928  const char *view_name = colormanage_view_get_default_name(display);
929  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
930  OCIO_ConstProcessorRcPtr *processor = NULL;
931 
932  if (view_name && config) {
933  const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(
934  config, display->name, view_name);
936  config, global_role_scene_linear, view_colorspace);
937 
938  OCIO_configRelease(config);
939  }
940 
941  if (processor != NULL) {
942  display->from_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
944  OCIO_processorRelease(processor);
945  }
946  }
947 
949  }
950 
951  return (OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear;
952 }
953 
954 static OCIO_ConstCPUProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display)
955 {
956  if (display->to_scene_linear == NULL) {
958 
959  if (display->to_scene_linear == NULL) {
960  const char *view_name = colormanage_view_get_default_name(display);
961  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
962  OCIO_ConstProcessorRcPtr *processor = NULL;
963 
964  if (view_name && config) {
965  const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(
966  config, display->name, view_name);
968  config, view_colorspace, global_role_scene_linear);
969 
970  OCIO_configRelease(config);
971  }
972 
973  if (processor != NULL) {
974  display->to_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
976  OCIO_processorRelease(processor);
977  }
978  }
979 
981  }
982 
983  return (OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear;
984 }
985 
987  ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
988 {
989  /* First, try use "Standard" view transform of the requested device. */
991  display_settings->display_device, "Standard");
992  /* If that fails, we fall back to the default view transform of the display
993  * as per OCIO configuration. */
994  if (default_view == NULL) {
996  if (display != NULL) {
997  default_view = colormanage_view_get_default(display);
998  }
999  }
1000  if (default_view != NULL) {
1001  BLI_strncpy(
1002  view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1003  }
1004  else {
1005  view_settings->view_transform[0] = '\0';
1006  }
1007  /* TODO(sergey): Find a way to safely/reliable un-hardcode this. */
1008  BLI_strncpy(view_settings->look, "None", sizeof(view_settings->look));
1009  /* Initialize rest of the settings. */
1010  view_settings->flag = 0;
1011  view_settings->gamma = 1.0f;
1012  view_settings->exposure = 0.0f;
1013  view_settings->curve_mapping = NULL;
1014 }
1015 
1016 static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
1017 {
1018  if (channels == 1) {
1019  pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1020  }
1021  else if (channels == 2) {
1022  pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1023  pixel[1] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[1]);
1024  }
1025  else {
1026  BKE_curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
1027  }
1028 }
1029 
1030 void colorspace_set_default_role(char *colorspace, int size, int role)
1031 {
1032  if (colorspace && colorspace[0] == '\0') {
1033  const char *role_colorspace;
1034 
1035  role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
1036 
1037  BLI_strncpy(colorspace, role_colorspace, size);
1038  }
1039 }
1040 
1042 {
1044 }
1045 
1046 void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
1047 {
1048  ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace);
1049 
1050  if (colorspace && colorspace->is_data) {
1052  return;
1053  }
1054 
1055  if (ibuf->rect_float) {
1056  const char *to_colorspace = global_role_scene_linear;
1057  const bool predivide = IMB_alpha_affects_rgb(ibuf);
1058 
1059  if (ibuf->rect) {
1060  imb_freerectImBuf(ibuf);
1061  }
1062 
1064  ibuf->x,
1065  ibuf->y,
1066  ibuf->channels,
1067  from_colorspace,
1068  to_colorspace,
1069  predivide);
1070  }
1071 }
1072 
1075 /* -------------------------------------------------------------------- */
1080  const char *what,
1081  const ColorManagedDisplay *default_display)
1082 {
1083  if (display_settings->display_device[0] == '\0') {
1084  BLI_strncpy(display_settings->display_device,
1085  default_display->name,
1086  sizeof(display_settings->display_device));
1087  }
1088  else {
1090 
1091  if (!display) {
1092  printf(
1093  "Color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
1094  display_settings->display_device,
1095  what,
1096  default_display->name);
1097 
1098  BLI_strncpy(display_settings->display_device,
1099  default_display->name,
1100  sizeof(display_settings->display_device));
1101  }
1102  }
1103 }
1104 
1106  ColorManagedViewSettings *view_settings,
1107  const char *what)
1108 {
1109  ColorManagedDisplay *display;
1110  ColorManagedView *default_view = NULL;
1112 
1113  if (view_settings->view_transform[0] == '\0') {
1114  display = colormanage_display_get_named(display_settings->display_device);
1115 
1116  if (display) {
1117  default_view = colormanage_view_get_default(display);
1118  }
1119 
1120  if (default_view) {
1121  BLI_strncpy(view_settings->view_transform,
1122  default_view->name,
1123  sizeof(view_settings->view_transform));
1124  }
1125  }
1126  else {
1128 
1129  if (!view) {
1130  display = colormanage_display_get_named(display_settings->display_device);
1131 
1132  if (display) {
1133  default_view = colormanage_view_get_default(display);
1134  }
1135 
1136  if (default_view) {
1137  printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
1138  what,
1139  view_settings->view_transform,
1140  default_view->name);
1141 
1142  BLI_strncpy(view_settings->view_transform,
1143  default_view->name,
1144  sizeof(view_settings->view_transform));
1145  }
1146  }
1147  }
1148 
1149  if (view_settings->look[0] == '\0') {
1150  BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1151  }
1152  else {
1153  ColorManagedLook *look = colormanage_look_get_named(view_settings->look);
1154  if (look == NULL) {
1155  printf("Color management: %s look \"%s\" not found, setting default \"%s\".\n",
1156  what,
1157  view_settings->look,
1158  default_look->name);
1159 
1160  BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1161  }
1162  }
1163 
1164  /* OCIO_TODO: move to do_versions() */
1165  if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
1166  view_settings->exposure = 0.0f;
1167  view_settings->gamma = 1.0f;
1168  }
1169 }
1170 
1172  ColorManagedColorspaceSettings *colorspace_settings, const char *what)
1173 {
1174  if (colorspace_settings->name[0] == '\0') {
1175  /* pass */
1176  }
1177  else {
1178  ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
1179 
1180  if (!colorspace) {
1181  printf("Color management: %s colorspace \"%s\" not found, will use default instead.\n",
1182  what,
1183  colorspace_settings->name);
1184 
1185  BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
1186  }
1187  }
1188 
1189  (void)what;
1190 }
1191 
1193 {
1194  Scene *scene;
1195  Image *image;
1196  MovieClip *clip;
1197 
1198  ColorManagedDisplay *default_display;
1199 
1200  default_display = colormanage_display_get_default();
1201 
1202  if (!default_display) {
1203  /* happens when OCIO configuration is incorrect */
1204  return;
1205  }
1206 
1207  for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
1208  ColorManagedColorspaceSettings *sequencer_colorspace_settings;
1209 
1210  /* check scene color management settings */
1211  colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
1213 
1214  sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
1215 
1216  colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
1217 
1218  if (sequencer_colorspace_settings->name[0] == '\0') {
1219  BLI_strncpy(
1220  sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
1221  }
1222 
1223  /* check sequencer strip input color space settings */
1224  Sequence *seq;
1225  SEQ_ALL_BEGIN (scene->ed, seq) {
1226  if (seq->strip) {
1228  }
1229  }
1230  SEQ_ALL_END;
1231  }
1232 
1233  /* ** check input color space settings ** */
1234 
1235  for (image = bmain->images.first; image; image = image->id.next) {
1237  }
1238 
1239  for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
1241  }
1242 }
1243 
1245  ColorManagedViewSettings *view_settings)
1246 {
1247  ColorManagedDisplay *display;
1248  ColorManagedView *default_view = NULL;
1249  LinkData *view_link;
1250 
1251  display = colormanage_display_get_named(display_settings->display_device);
1252 
1253  default_view = colormanage_view_get_default(display);
1254 
1255  for (view_link = display->views.first; view_link; view_link = view_link->next) {
1256  ColorManagedView *view = view_link->data;
1257 
1258  if (STREQ(view->name, view_settings->view_transform)) {
1259  break;
1260  }
1261  }
1262 
1263  if (view_link == NULL && default_view) {
1264  BLI_strncpy(
1265  view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1266  }
1267 }
1268 
1270 {
1271  switch (role) {
1272  case COLOR_ROLE_DATA:
1273  return global_role_data;
1275  return global_role_scene_linear;
1285  return global_role_default_byte;
1286  default:
1287  printf("Unknown role was passed to %s\n", __func__);
1288  BLI_assert(0);
1289  break;
1290  }
1291 
1292  return NULL;
1293 }
1294 
1295 void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
1296 {
1297  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1298 
1299  if (colorspace && colorspace->is_data) {
1301  }
1302  else {
1304  }
1305 }
1306 
1308 {
1313  if (ibuf_src->flags & IB_alphamode_premul) {
1314  ibuf_dst->flags |= IB_alphamode_premul;
1315  }
1316  else if (ibuf_src->flags & IB_alphamode_channel_packed) {
1317  ibuf_dst->flags |= IB_alphamode_channel_packed;
1318  }
1319  else if (ibuf_src->flags & IB_alphamode_ignore) {
1320  ibuf_dst->flags |= IB_alphamode_ignore;
1321  }
1322 }
1323 
1325 {
1326  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1327 
1328  ibuf->float_colorspace = colorspace;
1329 
1330  if (colorspace && colorspace->is_data) {
1332  }
1333  else {
1335  }
1336 }
1337 
1339 {
1340  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1341 
1342  ibuf->rect_colorspace = colorspace;
1343 
1344  if (colorspace && colorspace->is_data) {
1346  }
1347  else {
1349  }
1350 }
1351 
1353 {
1354  if (ibuf->float_colorspace) {
1355  return ibuf->float_colorspace->name;
1356  }
1357 
1359 }
1360 
1362 {
1363  if (ibuf->rect_colorspace) {
1364  return ibuf->rect_colorspace->name;
1365  }
1366 
1368 }
1369 
1371 {
1372  return (colorspace && colorspace->is_data);
1373 }
1374 
1376 {
1377  if (!colorspace->info.cached) {
1378  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1379  OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config,
1380  colorspace->name);
1381 
1382  bool is_scene_linear, is_srgb;
1383  OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb);
1384 
1385  OCIO_colorSpaceRelease(ocio_colorspace);
1386  OCIO_configRelease(config);
1387 
1388  colorspace->info.is_scene_linear = is_scene_linear;
1389  colorspace->info.is_srgb = is_srgb;
1390  colorspace->info.cached = true;
1391  }
1392 }
1393 
1395 {
1397  return (colorspace && colorspace->info.is_scene_linear);
1398 }
1399 
1401 {
1403  return (colorspace && colorspace->info.is_srgb);
1404 }
1405 
1407 {
1408  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1409  return (colorspace && colorspace->is_data);
1410 }
1411 
1413 {
1414  return &imbuf_xyz_to_rgb[0][0];
1415 }
1416 
1419 /* -------------------------------------------------------------------- */
1423 typedef struct DisplayBufferThread {
1425 
1426  const float *buffer;
1427  unsigned char *byte_buffer;
1428 
1430  unsigned char *display_buffer_byte;
1431 
1432  int width;
1435 
1437  float dither;
1438  bool is_data;
1440 
1441  const char *byte_colorspace;
1442  const char *float_colorspace;
1444 
1445 typedef struct DisplayBufferInitData {
1448  const float *buffer;
1449  unsigned char *byte_buffer;
1450 
1452  unsigned char *display_buffer_byte;
1453 
1454  int width;
1455 
1456  const char *byte_colorspace;
1457  const char *float_colorspace;
1459 
1460 static void display_buffer_init_handle(void *handle_v,
1461  int start_line,
1462  int tot_line,
1463  void *init_data_v)
1464 {
1465  DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1467  ImBuf *ibuf = init_data->ibuf;
1468 
1469  int channels = ibuf->channels;
1470  float dither = ibuf->dither;
1471  bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
1472 
1473  size_t offset = ((size_t)channels) * start_line * ibuf->x;
1474  size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
1475 
1476  memset(handle, 0, sizeof(DisplayBufferThread));
1477 
1478  handle->cm_processor = init_data->cm_processor;
1479 
1480  if (init_data->buffer) {
1481  handle->buffer = init_data->buffer + offset;
1482  }
1483 
1484  if (init_data->byte_buffer) {
1485  handle->byte_buffer = init_data->byte_buffer + offset;
1486  }
1487 
1488  if (init_data->display_buffer) {
1489  handle->display_buffer = init_data->display_buffer + offset;
1490  }
1491 
1492  if (init_data->display_buffer_byte) {
1493  handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
1494  }
1495 
1496  handle->width = ibuf->x;
1497 
1498  handle->start_line = start_line;
1499  handle->tot_line = tot_line;
1500 
1501  handle->channels = channels;
1502  handle->dither = dither;
1503  handle->is_data = is_data;
1504  handle->predivide = IMB_alpha_affects_rgb(ibuf);
1505 
1506  handle->byte_colorspace = init_data->byte_colorspace;
1507  handle->float_colorspace = init_data->float_colorspace;
1508 }
1509 
1511  int height,
1512  float *linear_buffer,
1513  bool *is_straight_alpha)
1514 {
1515  int channels = handle->channels;
1516  int width = handle->width;
1517 
1518  size_t buffer_size = ((size_t)channels) * width * height;
1519 
1520  bool is_data = handle->is_data;
1521  bool is_data_display = handle->cm_processor->is_data_result;
1522  bool predivide = handle->predivide;
1523 
1524  if (!handle->buffer) {
1525  unsigned char *byte_buffer = handle->byte_buffer;
1526 
1527  const char *from_colorspace = handle->byte_colorspace;
1528  const char *to_colorspace = global_role_scene_linear;
1529 
1530  float *fp;
1531  unsigned char *cp;
1532  const size_t i_last = ((size_t)width) * height;
1533  size_t i;
1534 
1535  /* first convert byte buffer to float, keep in image space */
1536  for (i = 0, fp = linear_buffer, cp = byte_buffer; i != i_last;
1537  i++, fp += channels, cp += channels) {
1538  if (channels == 3) {
1539  rgb_uchar_to_float(fp, cp);
1540  }
1541  else if (channels == 4) {
1542  rgba_uchar_to_float(fp, cp);
1543  }
1544  else {
1545  BLI_assert(!"Buffers of 3 or 4 channels are only supported here");
1546  }
1547  }
1548 
1549  if (!is_data && !is_data_display) {
1550  /* convert float buffer to scene linear space */
1552  linear_buffer, width, height, channels, from_colorspace, to_colorspace, false);
1553  }
1554 
1555  *is_straight_alpha = true;
1556  }
1557  else if (handle->float_colorspace) {
1558  /* currently float is non-linear only in sequencer, which is working
1559  * in its own color space even to handle float buffers.
1560  * This color space is the same for byte and float images.
1561  * Need to convert float buffer to linear space before applying display transform
1562  */
1563 
1564  const char *from_colorspace = handle->float_colorspace;
1565  const char *to_colorspace = global_role_scene_linear;
1566 
1567  memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1568 
1569  if (!is_data && !is_data_display) {
1571  linear_buffer, width, height, channels, from_colorspace, to_colorspace, predivide);
1572  }
1573 
1574  *is_straight_alpha = false;
1575  }
1576  else {
1577  /* some processors would want to modify float original buffer
1578  * before converting it into display byte buffer, so we need to
1579  * make sure original's ImBuf buffers wouldn't be modified by
1580  * using duplicated buffer here
1581  */
1582 
1583  memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1584 
1585  *is_straight_alpha = false;
1586  }
1587 }
1588 
1589 static void *do_display_buffer_apply_thread(void *handle_v)
1590 {
1591  DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1592  ColormanageProcessor *cm_processor = handle->cm_processor;
1593  float *display_buffer = handle->display_buffer;
1594  unsigned char *display_buffer_byte = handle->display_buffer_byte;
1595  int channels = handle->channels;
1596  int width = handle->width;
1597  int height = handle->tot_line;
1598  float dither = handle->dither;
1599  bool is_data = handle->is_data;
1600 
1601  if (cm_processor == NULL) {
1602  if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
1603  IMB_buffer_byte_from_byte(display_buffer_byte,
1604  handle->byte_buffer,
1607  false,
1608  width,
1609  height,
1610  width,
1611  width);
1612  }
1613 
1614  if (display_buffer) {
1615  IMB_buffer_float_from_byte(display_buffer,
1616  handle->byte_buffer,
1619  false,
1620  width,
1621  height,
1622  width,
1623  width);
1624  }
1625  }
1626  else {
1627  bool is_straight_alpha;
1628  float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
1629  "color conversion linear buffer");
1630 
1631  display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
1632 
1633  bool predivide = handle->predivide && (is_straight_alpha == false);
1634 
1635  if (is_data) {
1636  /* special case for data buffers - no color space conversions,
1637  * only generate byte buffers
1638  */
1639  }
1640  else {
1641  /* apply processor */
1643  cm_processor, linear_buffer, width, height, channels, predivide);
1644  }
1645 
1646  /* copy result to output buffers */
1647  if (display_buffer_byte) {
1648  /* do conversion */
1649  IMB_buffer_byte_from_float(display_buffer_byte,
1650  linear_buffer,
1651  channels,
1652  dither,
1655  predivide,
1656  width,
1657  height,
1658  width,
1659  width);
1660  }
1661 
1662  if (display_buffer) {
1663  memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
1664 
1665  if (is_straight_alpha && channels == 4) {
1666  const size_t i_last = ((size_t)width) * height;
1667  size_t i;
1668  float *fp;
1669 
1670  for (i = 0, fp = display_buffer; i != i_last; i++, fp += channels) {
1672  }
1673  }
1674  }
1675 
1676  MEM_freeN(linear_buffer);
1677  }
1678 
1679  return NULL;
1680 }
1681 
1683  const float *buffer,
1684  unsigned char *byte_buffer,
1685  float *display_buffer,
1686  unsigned char *display_buffer_byte,
1687  ColormanageProcessor *cm_processor)
1688 {
1690 
1691  init_data.ibuf = ibuf;
1692  init_data.cm_processor = cm_processor;
1693  init_data.buffer = buffer;
1694  init_data.byte_buffer = byte_buffer;
1695  init_data.display_buffer = display_buffer;
1696  init_data.display_buffer_byte = display_buffer_byte;
1697 
1698  if (ibuf->rect_colorspace != NULL) {
1699  init_data.byte_colorspace = ibuf->rect_colorspace->name;
1700  }
1701  else {
1702  /* happens for viewer images, which are not so simple to determine where to
1703  * set image buffer's color spaces
1704  */
1705  init_data.byte_colorspace = global_role_default_byte;
1706  }
1707 
1708  if (ibuf->float_colorspace != NULL) {
1709  /* sequencer stores float buffers in non-linear space */
1710  init_data.float_colorspace = ibuf->float_colorspace->name;
1711  }
1712  else {
1713  init_data.float_colorspace = NULL;
1714  }
1715 
1717  sizeof(DisplayBufferThread),
1718  &init_data,
1721 }
1722 
1724  const ColorManagedViewSettings *view_settings,
1725  const ColorManagedDisplaySettings *display_settings)
1726 {
1727  if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) == 0 &&
1728  view_settings->exposure == 0.0f && view_settings->gamma == 1.0f) {
1729  const char *from_colorspace = ibuf->rect_colorspace->name;
1730  const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings,
1731  display_settings);
1732  ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look);
1733  if (look_descr != NULL && !STREQ(look_descr->process_space, "")) {
1734  return false;
1735  }
1736 
1737  if (to_colorspace && STREQ(from_colorspace, to_colorspace)) {
1738  return true;
1739  }
1740  }
1741 
1742  return false;
1743 }
1744 
1746  ImBuf *ibuf,
1747  float *display_buffer,
1748  unsigned char *display_buffer_byte,
1749  const ColorManagedViewSettings *view_settings,
1750  const ColorManagedDisplaySettings *display_settings)
1751 {
1752  ColormanageProcessor *cm_processor = NULL;
1753  bool skip_transform = false;
1754 
1755  /* if we're going to transform byte buffer, check whether transformation would
1756  * happen to the same color space as byte buffer itself is
1757  * this would save byte -> float -> byte conversions making display buffer
1758  * computation noticeable faster
1759  */
1760  if (ibuf->rect_float == NULL && ibuf->rect_colorspace) {
1761  skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
1762  }
1763 
1764  if (skip_transform == false) {
1765  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1766  }
1767 
1769  ibuf->rect_float,
1770  (unsigned char *)ibuf->rect,
1771  display_buffer,
1772  display_buffer_byte,
1773  cm_processor);
1774 
1775  if (cm_processor) {
1776  IMB_colormanagement_processor_free(cm_processor);
1777  }
1778 }
1779 
1781  unsigned char *display_buffer,
1782  const ColorManagedViewSettings *view_settings,
1783  const ColorManagedDisplaySettings *display_settings)
1784 {
1786  ibuf, NULL, display_buffer, view_settings, display_settings);
1787 }
1788 
1791 /* -------------------------------------------------------------------- */
1797  unsigned char *byte_buffer;
1799  int width;
1806 
1807 typedef struct ProcessorTransformInit {
1809  unsigned char *byte_buffer;
1811  int width;
1812  int height;
1817 
1818 static void processor_transform_init_handle(void *handle_v,
1819  int start_line,
1820  int tot_line,
1821  void *init_data_v)
1822 {
1823  ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1825 
1826  const int channels = init_data->channels;
1827  const int width = init_data->width;
1828  const bool predivide = init_data->predivide;
1829  const bool float_from_byte = init_data->float_from_byte;
1830 
1831  const size_t offset = ((size_t)channels) * start_line * width;
1832 
1833  memset(handle, 0, sizeof(ProcessorTransformThread));
1834 
1835  handle->cm_processor = init_data->cm_processor;
1836 
1837  if (init_data->byte_buffer != NULL) {
1838  /* TODO(serge): Offset might be different for byte and float buffers. */
1839  handle->byte_buffer = init_data->byte_buffer + offset;
1840  }
1841  if (init_data->float_buffer != NULL) {
1842  handle->float_buffer = init_data->float_buffer + offset;
1843  }
1844 
1845  handle->width = width;
1846 
1847  handle->start_line = start_line;
1848  handle->tot_line = tot_line;
1849 
1850  handle->channels = channels;
1851  handle->predivide = predivide;
1852  handle->float_from_byte = float_from_byte;
1853 }
1854 
1855 static void *do_processor_transform_thread(void *handle_v)
1856 {
1857  ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1858  unsigned char *byte_buffer = handle->byte_buffer;
1859  float *float_buffer = handle->float_buffer;
1860  const int channels = handle->channels;
1861  const int width = handle->width;
1862  const int height = handle->tot_line;
1863  const bool predivide = handle->predivide;
1864  const bool float_from_byte = handle->float_from_byte;
1865 
1866  if (float_from_byte) {
1867  IMB_buffer_float_from_byte(float_buffer,
1868  byte_buffer,
1871  false,
1872  width,
1873  height,
1874  width,
1875  width);
1877  handle->cm_processor, float_buffer, width, height, channels, predivide);
1878  IMB_premultiply_rect_float(float_buffer, 4, width, height);
1879  }
1880  else {
1881  if (byte_buffer != NULL) {
1883  handle->cm_processor, byte_buffer, width, height, channels);
1884  }
1885  if (float_buffer != NULL) {
1887  handle->cm_processor, float_buffer, width, height, channels, predivide);
1888  }
1889  }
1890 
1891  return NULL;
1892 }
1893 
1894 static void processor_transform_apply_threaded(unsigned char *byte_buffer,
1895  float *float_buffer,
1896  const int width,
1897  const int height,
1898  const int channels,
1899  ColormanageProcessor *cm_processor,
1900  const bool predivide,
1901  const bool float_from_byte)
1902 {
1904 
1905  init_data.cm_processor = cm_processor;
1906  init_data.byte_buffer = byte_buffer;
1907  init_data.float_buffer = float_buffer;
1908  init_data.width = width;
1909  init_data.height = height;
1910  init_data.channels = channels;
1911  init_data.predivide = predivide;
1912  init_data.float_from_byte = float_from_byte;
1913 
1915  sizeof(ProcessorTransformThread),
1916  &init_data,
1919 }
1920 
1923 /* -------------------------------------------------------------------- */
1927 /* Convert the whole buffer from specified by name color space to another -
1928  * internal implementation. */
1929 static void colormanagement_transform_ex(unsigned char *byte_buffer,
1930  float *float_buffer,
1931  int width,
1932  int height,
1933  int channels,
1934  const char *from_colorspace,
1935  const char *to_colorspace,
1936  bool predivide,
1937  bool do_threaded)
1938 {
1939  ColormanageProcessor *cm_processor;
1940 
1941  if (from_colorspace[0] == '\0') {
1942  return;
1943  }
1944 
1945  if (STREQ(from_colorspace, to_colorspace)) {
1946  /* if source and destination color spaces are identical, skip
1947  * threading overhead and simply do nothing
1948  */
1949  return;
1950  }
1951 
1952  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1953 
1954  if (do_threaded) {
1956  byte_buffer, float_buffer, width, height, channels, cm_processor, predivide, false);
1957  }
1958  else {
1959  if (byte_buffer != NULL) {
1960  IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
1961  }
1962  if (float_buffer != NULL) {
1964  cm_processor, float_buffer, width, height, channels, predivide);
1965  }
1966  }
1967 
1968  IMB_colormanagement_processor_free(cm_processor);
1969 }
1970 
1971 /* convert the whole buffer from specified by name color space to another */
1973  int width,
1974  int height,
1975  int channels,
1976  const char *from_colorspace,
1977  const char *to_colorspace,
1978  bool predivide)
1979 {
1981  NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
1982 }
1983 
1984 /* convert the whole buffer from specified by name color space to another
1985  * will do threaded conversion
1986  */
1988  int width,
1989  int height,
1990  int channels,
1991  const char *from_colorspace,
1992  const char *to_colorspace,
1993  bool predivide)
1994 {
1996  NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
1997 }
1998 
1999 /* Similar to functions above, but operates on byte buffer. */
2001  int width,
2002  int height,
2003  int channels,
2004  const char *from_colorspace,
2005  const char *to_colorspace)
2006 {
2008  buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false);
2009 }
2011  int width,
2012  int height,
2013  int channels,
2014  const char *from_colorspace,
2015  const char *to_colorspace)
2016 {
2018  buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
2019 }
2020 
2021 /* Similar to above, but gets float buffer from display one. */
2023  unsigned char *byte_buffer,
2024  int width,
2025  int height,
2026  int channels,
2027  const char *from_colorspace,
2028  const char *to_colorspace)
2029 {
2030  IMB_buffer_float_from_byte(float_buffer,
2031  byte_buffer,
2034  true,
2035  width,
2036  height,
2037  width,
2038  width);
2040  float_buffer, width, height, channels, from_colorspace, to_colorspace, true);
2041 }
2043  unsigned char *byte_buffer,
2044  int width,
2045  int height,
2046  int channels,
2047  const char *from_colorspace,
2048  const char *to_colorspace)
2049 {
2050  ColormanageProcessor *cm_processor;
2051  if (from_colorspace == NULL || from_colorspace[0] == '\0') {
2052  return;
2053  }
2054  if (STREQ(from_colorspace, to_colorspace)) {
2055  /* Because this function always takes a byte buffer and returns a float buffer, it must
2056  * always do byte-to-float conversion of some kind. To avoid threading overhead
2057  * IMB_buffer_float_from_byte is used when color spaces are identical. See T51002.
2058  */
2059  IMB_buffer_float_from_byte(float_buffer,
2060  byte_buffer,
2063  false,
2064  width,
2065  height,
2066  width,
2067  width);
2068  IMB_premultiply_rect_float(float_buffer, 4, width, height);
2069  return;
2070  }
2071  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2073  byte_buffer, float_buffer, width, height, channels, cm_processor, false, true);
2074  IMB_colormanagement_processor_free(cm_processor);
2075 }
2076 
2078  const char *from_colorspace,
2079  const char *to_colorspace)
2080 {
2081  ColormanageProcessor *cm_processor;
2082 
2083  if (from_colorspace[0] == '\0') {
2084  return;
2085  }
2086 
2087  if (STREQ(from_colorspace, to_colorspace)) {
2088  /* if source and destination color spaces are identical, skip
2089  * threading overhead and simply do nothing
2090  */
2091  return;
2092  }
2093 
2094  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2095 
2096  IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2097 
2098  IMB_colormanagement_processor_free(cm_processor);
2099 }
2100 
2101 /* convert pixel from specified by descriptor color space to scene linear
2102  * used by performance-critical areas such as renderer and baker
2103  */
2105 {
2106  OCIO_ConstCPUProcessorRcPtr *processor;
2107 
2108  if (!colorspace) {
2109  /* should never happen */
2110  printf("%s: perform conversion from unknown color space\n", __func__);
2111  return;
2112  }
2113 
2114  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2115 
2116  if (processor != NULL) {
2117  OCIO_cpuProcessorApplyRGB(processor, pixel);
2118  }
2119 }
2120 
2121 /* same as above, but converts colors in opposite direction */
2123 {
2124  OCIO_ConstCPUProcessorRcPtr *processor;
2125 
2126  if (!colorspace) {
2127  /* should never happen */
2128  printf("%s: perform conversion from unknown color space\n", __func__);
2129  return;
2130  }
2131 
2132  processor = colorspace_from_scene_linear_cpu_processor(colorspace);
2133 
2134  if (processor != NULL) {
2135  OCIO_cpuProcessorApplyRGB(processor, pixel);
2136  }
2137 }
2138 
2140  bool predivide,
2141  ColorSpace *colorspace)
2142 {
2143  OCIO_ConstCPUProcessorRcPtr *processor;
2144 
2145  if (!colorspace) {
2146  /* should never happen */
2147  printf("%s: perform conversion from unknown color space\n", __func__);
2148  return;
2149  }
2150 
2151  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2152 
2153  if (processor != NULL) {
2154  if (predivide) {
2155  OCIO_cpuProcessorApplyRGBA_predivide(processor, pixel);
2156  }
2157  else {
2158  OCIO_cpuProcessorApplyRGBA(processor, pixel);
2159  }
2160  }
2161 }
2162 
2164  int width,
2165  int height,
2166  int channels,
2167  struct ColorSpace *colorspace,
2168  bool predivide)
2169 {
2170  OCIO_ConstCPUProcessorRcPtr *processor;
2171 
2172  if (!colorspace) {
2173  /* should never happen */
2174  printf("%s: perform conversion from unknown color space\n", __func__);
2175  return;
2176  }
2177 
2178  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2179 
2180  if (processor != NULL) {
2181  OCIO_PackedImageDesc *img;
2182 
2184  width,
2185  height,
2186  channels,
2187  sizeof(float),
2188  (size_t)channels * sizeof(float),
2189  (size_t)channels * sizeof(float) * width);
2190 
2191  if (predivide) {
2192  OCIO_cpuProcessorApply_predivide(processor, img);
2193  }
2194  else {
2195  OCIO_cpuProcessorApply(processor, img);
2196  }
2197 
2199  }
2200 }
2201 
2202 void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
2203  const int offset_x,
2204  const int offset_y,
2205  const int width,
2206  const int height,
2207  const struct ImBuf *ibuf,
2208  const bool compress_as_srgb,
2209  const bool store_premultiplied)
2210 {
2211  /* Convert byte buffer for texture storage on the GPU. These have builtin
2212  * support for converting sRGB to linear, which allows us to store textures
2213  * without precision or performance loss at minimal memory usage. */
2214  BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
2215 
2216  OCIO_ConstCPUProcessorRcPtr *processor = NULL;
2217  if (compress_as_srgb && ibuf->rect_colorspace &&
2220  }
2221 
2222  /* TODO(brecht): make this multi-threaded, or at least process in batches. */
2223  const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
2224  const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
2225 
2226  for (int y = 0; y < height; y++) {
2227  const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2228  const size_t out_offset = y * width;
2229  const unsigned char *in = in_buffer + in_offset * 4;
2230  unsigned char *out = out_buffer + out_offset * 4;
2231 
2232  if (processor != NULL) {
2233  /* Convert to scene linear, to sRGB and premultiply. */
2234  for (int x = 0; x < width; x++, in += 4, out += 4) {
2235  float pixel[4];
2236  rgba_uchar_to_float(pixel, in);
2237  OCIO_cpuProcessorApplyRGB(processor, pixel);
2238  linearrgb_to_srgb_v3_v3(pixel, pixel);
2239  if (use_premultiply) {
2240  mul_v3_fl(pixel, pixel[3]);
2241  }
2242  rgba_float_to_uchar(out, pixel);
2243  }
2244  }
2245  else if (use_premultiply) {
2246  /* Premultiply only. */
2247  for (int x = 0; x < width; x++, in += 4, out += 4) {
2248  out[0] = (in[0] * in[3]) >> 8;
2249  out[1] = (in[1] * in[3]) >> 8;
2250  out[2] = (in[2] * in[3]) >> 8;
2251  out[3] = in[3];
2252  }
2253  }
2254  else {
2255  /* Copy only. */
2256  for (int x = 0; x < width; x++, in += 4, out += 4) {
2257  out[0] = in[0];
2258  out[1] = in[1];
2259  out[2] = in[2];
2260  out[3] = in[3];
2261  }
2262  }
2263  }
2264 }
2265 
2267  const int offset_x,
2268  const int offset_y,
2269  const int width,
2270  const int height,
2271  const struct ImBuf *ibuf,
2272  const bool store_premultiplied)
2273 {
2274  /* Float texture are stored in scene linear color space, with premultiplied
2275  * alpha depending on the image alpha mode. */
2276  const float *in_buffer = ibuf->rect_float;
2277  const int in_channels = ibuf->channels;
2278  const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
2279 
2280  for (int y = 0; y < height; y++) {
2281  const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2282  const size_t out_offset = y * width;
2283  const float *in = in_buffer + in_offset * in_channels;
2284  float *out = out_buffer + out_offset * 4;
2285 
2286  if (in_channels == 1) {
2287  /* Copy single channel. */
2288  for (int x = 0; x < width; x++, in += 1, out += 4) {
2289  out[0] = in[0];
2290  out[1] = in[0];
2291  out[2] = in[0];
2292  out[3] = in[0];
2293  }
2294  }
2295  else if (in_channels == 3) {
2296  /* Copy RGB. */
2297  for (int x = 0; x < width; x++, in += 3, out += 4) {
2298  out[0] = in[0];
2299  out[1] = in[1];
2300  out[2] = in[2];
2301  out[3] = 1.0f;
2302  }
2303  }
2304  else if (in_channels == 4) {
2305  /* Copy or convert RGBA. */
2306  if (use_unpremultiply) {
2307  for (int x = 0; x < width; x++, in += 4, out += 4) {
2308  premul_to_straight_v4_v4(out, in);
2309  }
2310  }
2311  else {
2312  memcpy(out, in, sizeof(float[4]) * width);
2313  }
2314  }
2315  }
2316 }
2317 
2318 /* Conversion between color picking role. Typically we would expect such a
2319  * requirements:
2320  * - It is approximately perceptually linear, so that the HSV numbers and
2321  * the HSV cube/circle have an intuitive distribution.
2322  * - It has the same gamut as the scene linear color space.
2323  * - Color picking values 0..1 map to scene linear values in the 0..1 range,
2324  * so that picked albedo values are energy conserving.
2325  */
2327 {
2329  /* Create processor if none exists. */
2331 
2333  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2335 
2336  if (processor != NULL) {
2338  OCIO_processorRelease(processor);
2339  }
2340  else {
2342  }
2343  }
2344 
2346  }
2347 
2350  }
2351 }
2352 
2354 {
2356  /* Create processor if none exists. */
2358 
2360  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2362 
2363  if (processor != NULL) {
2365  OCIO_processorRelease(processor);
2366  }
2367  else {
2369  }
2370  }
2371 
2373  }
2374 
2377  }
2378 }
2379 
2380 /* Conversion between sRGB, for rare cases like hex color or copy/pasting
2381  * between UI theme and scene linear colors. */
2383 {
2384  mul_m3_v3(imbuf_rgb_to_xyz, pixel);
2386  linearrgb_to_srgb_v3_v3(pixel, pixel);
2387 }
2388 
2390 {
2391  srgb_to_linearrgb_v3_v3(pixel, pixel);
2393  mul_m3_v3(imbuf_xyz_to_rgb, pixel);
2394 }
2395 
2396 /* convert pixel from scene linear to display space using default view
2397  * used by performance-critical areas such as color-related widgets where we want to reduce
2398  * amount of per-widget allocations
2399  */
2401 {
2402  OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
2403 
2404  if (processor != NULL) {
2405  OCIO_cpuProcessorApplyRGB(processor, pixel);
2406  }
2407 }
2408 
2409 /* same as above, but converts color in opposite direction */
2411 {
2412  OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
2413 
2414  if (processor != NULL) {
2415  OCIO_cpuProcessorApplyRGB(processor, pixel);
2416  }
2417 }
2418 
2420  float result[4],
2421  const float pixel[4],
2422  const ColorManagedViewSettings *view_settings,
2423  const ColorManagedDisplaySettings *display_settings)
2424 {
2425  ColormanageProcessor *cm_processor;
2426 
2427  copy_v4_v4(result, pixel);
2428 
2429  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2431  IMB_colormanagement_processor_free(cm_processor);
2432 }
2433 
2435  float result[3],
2436  const float pixel[3],
2437  const ColorManagedViewSettings *view_settings,
2438  const ColorManagedDisplaySettings *display_settings)
2439 {
2440  ColormanageProcessor *cm_processor;
2441 
2442  copy_v3_v3(result, pixel);
2443 
2444  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2446  IMB_colormanagement_processor_free(cm_processor);
2447 }
2448 
2450  ImBuf *ibuf,
2451  const ColorManagedViewSettings *view_settings,
2452  const ColorManagedDisplaySettings *display_settings,
2453  bool make_byte)
2454 {
2455  if (!ibuf->rect && make_byte) {
2456  imb_addrectImBuf(ibuf);
2457  }
2458 
2460  ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect, view_settings, display_settings);
2461 }
2462 
2464  ImBuf *ibuf,
2465  const ColorManagedViewSettings *view_settings,
2466  const ColorManagedDisplaySettings *display_settings)
2467 {
2468  colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
2469 }
2470 
2471 /* prepare image buffer to be saved on disk, applying color management if needed
2472  * color management would be applied if image is saving as render result and if
2473  * file format is not expecting float buffer to be in linear space (currently
2474  * JPEG2000 and TIFF are such formats -- they're storing image as float but
2475  * file itself stores applied color space).
2476  *
2477  * Both byte and float buffers would contain applied color space, and result's
2478  * float_colorspace would be set to display color space. This should be checked
2479  * in image format write callback and if float_colorspace is not NULL, no color
2480  * space transformation should be applied on this buffer.
2481  */
2483  bool save_as_render,
2484  bool allocate_result,
2485  const ColorManagedViewSettings *view_settings,
2486  const ColorManagedDisplaySettings *display_settings,
2487  ImageFormatData *image_format_data)
2488 {
2489  ImBuf *colormanaged_ibuf = ibuf;
2490  bool do_colormanagement;
2491  bool is_movie = BKE_imtype_is_movie(image_format_data->imtype);
2492  bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
2493  bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
2494 
2495  if (ibuf->rect_float && ibuf->rect &&
2497  IMB_rect_from_float(ibuf);
2499  }
2500 
2501  do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
2502 
2503  if (do_colormanagement || do_alpha_under) {
2504  if (allocate_result) {
2505  colormanaged_ibuf = IMB_dupImBuf(ibuf);
2506  }
2507  else {
2508  /* Render pipeline is constructing image buffer itself,
2509  * but it's re-using byte and float buffers from render result make copy of this buffers
2510  * here sine this buffers would be transformed to other color space here.
2511  */
2512 
2513  if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
2514  ibuf->rect = MEM_dupallocN(ibuf->rect);
2515  ibuf->mall |= IB_rect;
2516  }
2517 
2518  if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
2519  ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
2520  ibuf->mall |= IB_rectfloat;
2521  }
2522  }
2523  }
2524 
2525  /* If we're saving from RGBA to RGB buffer then it's not
2526  * so much useful to just ignore alpha -- it leads to bad
2527  * artifacts especially when saving byte images.
2528  *
2529  * What we do here is we're overlaying our image on top of
2530  * background color (which is currently black).
2531  *
2532  * This is quite much the same as what Gimp does and it
2533  * seems to be what artists expects from saving.
2534  *
2535  * Do a conversion here, so image format writers could
2536  * happily assume all the alpha tricks were made already.
2537  * helps keep things locally here, not spreading it to
2538  * all possible image writers we've got.
2539  */
2540  if (do_alpha_under) {
2541  float color[3] = {0, 0, 0};
2542 
2543  if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
2545  colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
2546  }
2547 
2548  if (colormanaged_ibuf->rect) {
2549  IMB_alpha_under_color_byte((unsigned char *)colormanaged_ibuf->rect,
2550  colormanaged_ibuf->x,
2551  colormanaged_ibuf->y,
2552  color);
2553  }
2554  }
2555 
2556  if (do_colormanagement) {
2557  bool make_byte = false;
2558 
2559  /* for proper check whether byte buffer is required by a format or not
2560  * should be pretty safe since this image buffer is supposed to be used for
2561  * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
2562  */
2563  colormanaged_ibuf->ftype = BKE_image_imtype_to_ftype(image_format_data->imtype,
2564  &colormanaged_ibuf->foptions);
2565 
2566  /* if file format isn't able to handle float buffer itself,
2567  * we need to allocate byte buffer and store color managed
2568  * image there
2569  */
2570  const ImFileType *type = IMB_file_type_from_ibuf(colormanaged_ibuf);
2571  if (type != NULL) {
2572  if ((type->save != NULL) && (type->flag & IM_FTYPE_FLOAT) == 0) {
2573  make_byte = true;
2574  }
2575  }
2576 
2577  /* perform color space conversions */
2579  colormanaged_ibuf, view_settings, display_settings, make_byte);
2580 
2581  if (colormanaged_ibuf->rect_float) {
2582  /* float buffer isn't linear anymore,
2583  * image format write callback should check for this flag and assume
2584  * no space conversion should happen if ibuf->float_colorspace != NULL
2585  */
2586  colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings,
2587  display_settings);
2588  }
2589  }
2590 
2591  if (colormanaged_ibuf != ibuf) {
2592  IMB_metadata_copy(colormanaged_ibuf, ibuf);
2593  }
2594 
2595  return colormanaged_ibuf;
2596 }
2597 
2599  float *buffer,
2600  unsigned char *display_buffer,
2601  int width,
2602  int height,
2603  int channels,
2604  float dither,
2605  const ColorManagedViewSettings *view_settings,
2606  const ColorManagedDisplaySettings *display_settings)
2607 {
2608  ColormanageProcessor *cm_processor;
2609  size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
2610  float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
2611 
2612  /* TODO(sergey): Convert float directly to byte buffer. */
2613 
2614  memcpy(display_buffer_float, buffer, float_buffer_size);
2615 
2616  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2617 
2619  NULL, display_buffer_float, width, height, channels, cm_processor, true, false);
2620 
2621  IMB_buffer_byte_from_float(display_buffer,
2622  display_buffer_float,
2623  channels,
2624  dither,
2627  true,
2628  width,
2629  height,
2630  width,
2631  width);
2632 
2633  MEM_freeN(display_buffer_float);
2634  IMB_colormanagement_processor_free(cm_processor);
2635 }
2636 
2639 /* -------------------------------------------------------------------- */
2643 /* acquire display buffer for given image buffer using specified view and display settings */
2644 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
2645  const ColorManagedViewSettings *view_settings,
2646  const ColorManagedDisplaySettings *display_settings,
2647  void **cache_handle)
2648 {
2649  unsigned char *display_buffer;
2650  size_t buffer_size;
2651  ColormanageCacheViewSettings cache_view_settings;
2652  ColormanageCacheDisplaySettings cache_display_settings;
2653  ColorManagedViewSettings default_view_settings;
2654  const ColorManagedViewSettings *applied_view_settings;
2655 
2656  *cache_handle = NULL;
2657 
2658  if (!ibuf->x || !ibuf->y) {
2659  return NULL;
2660  }
2661 
2662  if (view_settings) {
2663  applied_view_settings = view_settings;
2664  }
2665  else {
2666  /* If no view settings were specified, use default ones, which will
2667  * attempt not to do any extra color correction. */
2668  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
2669  applied_view_settings = &default_view_settings;
2670  }
2671 
2672  /* early out: no float buffer and byte buffer is already in display space,
2673  * let's just use if
2674  */
2675  if (ibuf->rect_float == NULL && ibuf->rect_colorspace && ibuf->channels == 4) {
2676  if (is_ibuf_rect_in_display_space(ibuf, applied_view_settings, display_settings)) {
2677  return (unsigned char *)ibuf->rect;
2678  }
2679  }
2680 
2681  colormanage_view_settings_to_cache(ibuf, &cache_view_settings, applied_view_settings);
2682  colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
2683 
2684  if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) {
2685  if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
2687  ibuf->rect_float,
2688  (unsigned char *)ibuf->rect,
2689  ibuf->x,
2690  0,
2691  0,
2692  applied_view_settings,
2693  display_settings,
2694  ibuf->invalid_rect.xmin,
2695  ibuf->invalid_rect.ymin,
2696  ibuf->invalid_rect.xmax,
2697  ibuf->invalid_rect.ymax);
2698  }
2699 
2700  BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0);
2701  }
2702 
2704 
2705  /* ensure color management bit fields exists */
2706  if (!ibuf->display_buffer_flags) {
2707  ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display,
2708  "imbuf display_buffer_flags");
2709  }
2710  else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
2711  /* all display buffers were marked as invalid from other areas,
2712  * now propagate this flag to internal color management routines
2713  */
2714  memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
2715 
2717  }
2718 
2719  display_buffer = colormanage_cache_get(
2720  ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
2721 
2722  if (display_buffer) {
2724  return display_buffer;
2725  }
2726 
2727  buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
2728  display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
2729 
2731  ibuf, display_buffer, applied_view_settings, display_settings);
2732 
2734  ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
2735 
2737 
2738  return display_buffer;
2739 }
2740 
2741 /* same as IMB_display_buffer_acquire but gets view and display settings from context */
2742 unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
2743 {
2744  ColorManagedViewSettings *view_settings;
2745  ColorManagedDisplaySettings *display_settings;
2746 
2747  IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
2748 
2749  return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
2750 }
2751 
2752 void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
2753  float *linear_buffer,
2754  int width,
2755  int height,
2756  int channels,
2757  const ColorManagedViewSettings *view_settings,
2758  const ColorManagedDisplaySettings *display_settings,
2759  bool predivide)
2760 {
2761  float *buffer;
2763  display_settings);
2764 
2765  buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float),
2766  "display transform temp buffer");
2767  memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
2768 
2769  IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
2770 
2771  IMB_colormanagement_processor_free(cm_processor);
2772 
2773  IMB_buffer_byte_from_float(display_buffer,
2774  buffer,
2775  channels,
2776  0.0f,
2779  false,
2780  width,
2781  height,
2782  width,
2783  width);
2784 
2785  MEM_freeN(buffer);
2786 }
2787 
2788 void IMB_display_buffer_release(void *cache_handle)
2789 {
2790  if (cache_handle) {
2792 
2793  colormanage_cache_handle_release(cache_handle);
2794 
2796  }
2797 }
2798 
2801 /* -------------------------------------------------------------------- */
2806 {
2807  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2808  const char *display_name;
2809 
2810  display_name = OCIO_configGetDefaultDisplay(config);
2811 
2812  OCIO_configRelease(config);
2813 
2814  return display_name;
2815 }
2816 
2818 {
2819  const char *display_name = colormanage_display_get_default_name();
2820 
2821  if (display_name[0] == '\0') {
2822  return NULL;
2823  }
2824 
2825  return colormanage_display_get_named(display_name);
2826 }
2827 
2829 {
2830  ColorManagedDisplay *display;
2831  int index = 0;
2832 
2833  if (global_displays.last) {
2834  ColorManagedDisplay *last_display = global_displays.last;
2835 
2836  index = last_display->index;
2837  }
2838 
2839  display = MEM_callocN(sizeof(ColorManagedDisplay), "ColorManagedDisplay");
2840 
2841  display->index = index + 1;
2842 
2843  BLI_strncpy(display->name, name, sizeof(display->name));
2844 
2845  BLI_addtail(&global_displays, display);
2846 
2847  return display;
2848 }
2849 
2851 {
2852  ColorManagedDisplay *display;
2853 
2854  for (display = global_displays.first; display; display = display->next) {
2855  if (STREQ(display->name, name)) {
2856  return display;
2857  }
2858  }
2859 
2860  return NULL;
2861 }
2862 
2864 {
2865  /* display indices are 1-based */
2866  return BLI_findlink(&global_displays, index - 1);
2867 }
2868 
2870 {
2871  ColorManagedDisplay *display;
2872 
2873  display = colormanage_display_get_named(name);
2874 
2875  if (display) {
2876  return display->index;
2877  }
2878 
2879  return 0;
2880 }
2881 
2883 {
2884  ColorManagedDisplay *display;
2885 
2886  display = colormanage_display_get_indexed(index);
2887 
2888  if (display) {
2889  return display->name;
2890  }
2891 
2892  return NULL;
2893 }
2894 
2896 {
2898 
2899  return display->name;
2900 }
2901 
2902 /* used by performance-critical pixel processing areas, such as color widgets */
2904 {
2905  return colormanage_display_get_named(name);
2906 }
2907 
2909 {
2910  if (colormanage_display_get_named("None") != NULL) {
2911  return "None";
2912  }
2913 
2915 }
2916 
2918  struct ColorManagedDisplay *display)
2919 {
2920  return colormanage_view_get_default_name(display);
2921 }
2922 
2925 /* -------------------------------------------------------------------- */
2930 {
2931  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2932  const char *name;
2933 
2934  name = OCIO_configGetDefaultView(config, display->name);
2935 
2936  OCIO_configRelease(config);
2937 
2938  return name;
2939 }
2940 
2942 {
2943  const char *name = colormanage_view_get_default_name(display);
2944 
2945  if (!name || name[0] == '\0') {
2946  return NULL;
2947  }
2948 
2949  return colormanage_view_get_named(name);
2950 }
2951 
2953 {
2955  int index = global_tot_view;
2956 
2957  view = MEM_callocN(sizeof(ColorManagedView), "ColorManagedView");
2958  view->index = index + 1;
2959  BLI_strncpy(view->name, name, sizeof(view->name));
2960 
2962 
2963  global_tot_view++;
2964 
2965  return view;
2966 }
2967 
2969 {
2971 
2972  for (view = global_views.first; view; view = view->next) {
2973  if (STREQ(view->name, name)) {
2974  return view;
2975  }
2976  }
2977 
2978  return NULL;
2979 }
2980 
2982 {
2983  /* view transform indices are 1-based */
2984  return BLI_findlink(&global_views, index - 1);
2985 }
2986 
2988  const char *name)
2989 {
2990  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2991  if (display == NULL) {
2992  return NULL;
2993  }
2994  LISTBASE_FOREACH (LinkData *, view_link, &display->views) {
2995  ColorManagedView *view = view_link->data;
2996  if (STRCASEEQ(name, view->name)) {
2997  return view;
2998  }
2999  }
3000  return NULL;
3001 }
3002 
3004 {
3006 
3007  if (view) {
3008  return view->index;
3009  }
3010 
3011  return 0;
3012 }
3013 
3015 {
3017 
3018  if (view) {
3019  return view->name;
3020  }
3021 
3022  return NULL;
3023 }
3024 
3025 const char *IMB_colormanagement_view_get_default_name(const char *display_name)
3026 {
3027  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3029 
3030  if (display) {
3032  }
3033 
3034  if (view) {
3035  return view->name;
3036  }
3037 
3038  return NULL;
3039 }
3040 
3043 /* -------------------------------------------------------------------- */
3047 static void colormanage_description_strip(char *description)
3048 {
3049  int i, n;
3050 
3051  for (i = (int)strlen(description) - 1; i >= 0; i--) {
3052  if (ELEM(description[i], '\r', '\n')) {
3053  description[i] = '\0';
3054  }
3055  else {
3056  break;
3057  }
3058  }
3059 
3060  for (i = 0, n = strlen(description); i < n; i++) {
3061  if (ELEM(description[i], '\r', '\n')) {
3062  description[i] = ' ';
3063  }
3064  }
3065 }
3066 
3068  const char *description,
3069  bool is_invertible,
3070  bool is_data)
3071 {
3072  ColorSpace *colorspace, *prev_space;
3073  int counter = 1;
3074 
3075  colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace");
3076 
3077  BLI_strncpy(colorspace->name, name, sizeof(colorspace->name));
3078 
3079  if (description) {
3080  BLI_strncpy(colorspace->description, description, sizeof(colorspace->description));
3081 
3083  }
3084 
3085  colorspace->is_invertible = is_invertible;
3086  colorspace->is_data = is_data;
3087 
3088  for (prev_space = global_colorspaces.first; prev_space; prev_space = prev_space->next) {
3089  if (BLI_strcasecmp(prev_space->name, colorspace->name) > 0) {
3090  break;
3091  }
3092 
3093  prev_space->index = counter++;
3094  }
3095 
3096  if (!prev_space) {
3097  BLI_addtail(&global_colorspaces, colorspace);
3098  }
3099  else {
3100  BLI_insertlinkbefore(&global_colorspaces, prev_space, colorspace);
3101  }
3102 
3103  colorspace->index = counter++;
3104  for (; prev_space; prev_space = prev_space->next) {
3105  prev_space->index = counter++;
3106  }
3107 
3109 
3110  return colorspace;
3111 }
3112 
3114 {
3115  ColorSpace *colorspace;
3116 
3117  for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
3118  if (STREQ(colorspace->name, name)) {
3119  return colorspace;
3120  }
3121  }
3122 
3123  return NULL;
3124 }
3125 
3127 {
3128  const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
3129 
3130  return colormanage_colorspace_get_named(role_colorspace);
3131 }
3132 
3134 {
3135  /* color space indices are 1-based */
3136  return BLI_findlink(&global_colorspaces, index - 1);
3137 }
3138 
3140 {
3141  ColorSpace *colorspace;
3142 
3143  colorspace = colormanage_colorspace_get_named(name);
3144 
3145  if (colorspace) {
3146  return colorspace->index;
3147  }
3148 
3149  return 0;
3150 }
3151 
3153 {
3154  ColorSpace *colorspace;
3155 
3156  colorspace = colormanage_colorspace_get_indexed(index);
3157 
3158  if (colorspace) {
3159  return colorspace->name;
3160  }
3161 
3162  return "";
3163 }
3164 
3166  ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
3167 {
3168  /* Don't modify non-color data space, it does not change with file type. */
3169  ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
3170 
3171  if (colorspace && colorspace->is_data) {
3172  return;
3173  }
3174 
3175  /* Get color space from file type. */
3176  const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
3177  if (type != NULL) {
3178  if (type->save != NULL) {
3179  const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(
3180  type->default_save_role);
3181  BLI_strncpy(colorspace_settings->name, role_colorspace, sizeof(colorspace_settings->name));
3182  }
3183  }
3184 }
3185 
3188 /* -------------------------------------------------------------------- */
3192 ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop)
3193 {
3194  ColorManagedLook *look;
3195  int index = global_tot_looks;
3196 
3197  look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook");
3198  look->index = index + 1;
3199  BLI_strncpy(look->name, name, sizeof(look->name));
3200  BLI_strncpy(look->ui_name, name, sizeof(look->ui_name));
3201  BLI_strncpy(look->process_space, process_space, sizeof(look->process_space));
3202  look->is_noop = is_noop;
3203 
3204  /* Detect view specific looks. */
3205  const char *separator_offset = strstr(look->name, " - ");
3206  if (separator_offset) {
3207  BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
3208  BLI_strncpy(look->ui_name, separator_offset + strlen(" - "), sizeof(look->ui_name));
3209  }
3210 
3211  BLI_addtail(&global_looks, look);
3212 
3213  global_tot_looks++;
3214 
3215  return look;
3216 }
3217 
3219 {
3220  ColorManagedLook *look;
3221 
3222  for (look = global_looks.first; look; look = look->next) {
3223  if (STREQ(look->name, name)) {
3224  return look;
3225  }
3226  }
3227 
3228  return NULL;
3229 }
3230 
3232 {
3233  /* look indices are 1-based */
3234  return BLI_findlink(&global_looks, index - 1);
3235 }
3236 
3238 {
3239  ColorManagedLook *look;
3240 
3241  look = colormanage_look_get_named(name);
3242 
3243  if (look) {
3244  return look->index;
3245  }
3246 
3247  return 0;
3248 }
3249 
3251 {
3252  ColorManagedLook *look;
3253 
3254  look = colormanage_look_get_indexed(index);
3255 
3256  if (look) {
3257  return look->name;
3258  }
3259 
3260  return NULL;
3261 }
3262 
3265 /* -------------------------------------------------------------------- */
3270 {
3271  ColorManagedDisplay *display;
3272 
3273  for (display = global_displays.first; display; display = display->next) {
3274  EnumPropertyItem item;
3275 
3276  item.value = display->index;
3277  item.name = display->name;
3278  item.identifier = display->name;
3279  item.icon = 0;
3280  item.description = "";
3281 
3282  RNA_enum_item_add(items, totitem, &item);
3283  }
3284 }
3285 
3287  int *totitem,
3289 {
3290  EnumPropertyItem item;
3291 
3292  item.value = view->index;
3293  item.name = view->name;
3294  item.identifier = view->name;
3295  item.icon = 0;
3296  item.description = "";
3297 
3298  RNA_enum_item_add(items, totitem, &item);
3299 }
3300 
3302  int *totitem,
3303  const char *display_name)
3304 {
3305  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3307 
3308  if (display) {
3309  LinkData *display_view;
3310 
3311  for (display_view = display->views.first; display_view; display_view = display_view->next) {
3312  view = display_view->data;
3313 
3314  colormanagement_view_item_add(items, totitem, view);
3315  }
3316  }
3317 }
3318 
3320  int *totitem,
3321  const char *view_name)
3322 {
3323  ColorManagedLook *look;
3324 
3325  for (look = global_looks.first; look; look = look->next) {
3326  if (!colormanage_compatible_look(look, view_name)) {
3327  continue;
3328  }
3329 
3330  EnumPropertyItem item;
3331 
3332  item.value = look->index;
3333  item.name = look->ui_name;
3334  item.identifier = look->name;
3335  item.icon = 0;
3336  item.description = "";
3337 
3338  RNA_enum_item_add(items, totitem, &item);
3339  }
3340 }
3341 
3343 {
3344  ColorSpace *colorspace;
3345 
3346  for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
3347  EnumPropertyItem item;
3348 
3349  if (!colorspace->is_invertible) {
3350  continue;
3351  }
3352 
3353  item.value = colorspace->index;
3354  item.name = colorspace->name;
3355  item.identifier = colorspace->name;
3356  item.icon = 0;
3357  item.description = colorspace->description;
3358 
3359  RNA_enum_item_add(items, totitem, &item);
3360  }
3361 }
3362 
3365 /* -------------------------------------------------------------------- */
3369 /*
3370  * Partial display update is supposed to be used by such areas as
3371  * compositor and renderer, This areas are calculating tiles of the
3372  * images and because of performance reasons only this tiles should
3373  * be color managed.
3374  * This gives nice visual feedback without slowing things down.
3375  *
3376  * Updating happens for active display transformation only, all
3377  * the rest buffers would be marked as dirty
3378  */
3379 
3381  unsigned char *display_buffer,
3382  const float *linear_buffer,
3383  const unsigned char *byte_buffer,
3384  int display_stride,
3385  int linear_stride,
3386  int linear_offset_x,
3387  int linear_offset_y,
3388  ColormanageProcessor *cm_processor,
3389  const int xmin,
3390  const int ymin,
3391  const int xmax,
3392  const int ymax)
3393 {
3394  int x, y;
3395  int channels = ibuf->channels;
3396  float dither = ibuf->dither;
3397  ColorSpace *rect_colorspace = ibuf->rect_colorspace;
3398  float *display_buffer_float = NULL;
3399  const int width = xmax - xmin;
3400  const int height = ymax - ymin;
3401  bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3402 
3403  if (dither != 0.0f) {
3404  /* cm_processor is NULL in cases byte_buffer's space matches display
3405  * buffer's space
3406  * in this case we could skip extra transform and only apply dither
3407  * use 4 channels for easier byte->float->byte conversion here so
3408  * (this is only needed to apply dither, in other cases we'll convert
3409  * byte buffer to display directly)
3410  */
3411  if (!cm_processor) {
3412  channels = 4;
3413  }
3414 
3415  display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float),
3416  "display buffer for dither");
3417  }
3418 
3419  if (cm_processor) {
3420  for (y = ymin; y < ymax; y++) {
3421  for (x = xmin; x < xmax; x++) {
3422  size_t display_index = ((size_t)y * display_stride + x) * 4;
3423  size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride +
3424  (x - linear_offset_x)) *
3425  channels;
3426  float pixel[4];
3427 
3428  if (linear_buffer) {
3429  if (channels == 4) {
3430  copy_v4_v4(pixel, (float *)linear_buffer + linear_index);
3431  }
3432  else if (channels == 3) {
3433  copy_v3_v3(pixel, (float *)linear_buffer + linear_index);
3434  pixel[3] = 1.0f;
3435  }
3436  else if (channels == 1) {
3437  pixel[0] = linear_buffer[linear_index];
3438  }
3439  else {
3440  BLI_assert(!"Unsupported number of channels in partial buffer update");
3441  }
3442  }
3443  else if (byte_buffer) {
3444  rgba_uchar_to_float(pixel, byte_buffer + linear_index);
3445  IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
3446  straight_to_premul_v4(pixel);
3447  }
3448 
3449  if (!is_data) {
3450  IMB_colormanagement_processor_apply_pixel(cm_processor, pixel, channels);
3451  }
3452 
3453  if (display_buffer_float) {
3454  size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
3455 
3456  if (channels == 4) {
3457  copy_v4_v4(display_buffer_float + index, pixel);
3458  }
3459  else if (channels == 3) {
3460  copy_v3_v3(display_buffer_float + index, pixel);
3461  }
3462  else /* if (channels == 1) */ {
3463  display_buffer_float[index] = pixel[0];
3464  }
3465  }
3466  else {
3467  if (channels == 4) {
3468  float pixel_straight[4];
3469  premul_to_straight_v4_v4(pixel_straight, pixel);
3470  rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
3471  }
3472  else if (channels == 3) {
3473  rgb_float_to_uchar(display_buffer + display_index, pixel);
3474  display_buffer[display_index + 3] = 255;
3475  }
3476  else /* if (channels == 1) */ {
3477  display_buffer[display_index] = display_buffer[display_index + 1] =
3478  display_buffer[display_index + 2] = display_buffer[display_index + 3] =
3479  unit_float_to_uchar_clamp(pixel[0]);
3480  }
3481  }
3482  }
3483  }
3484  }
3485  else {
3486  if (display_buffer_float) {
3487  /* huh, for dither we need float buffer first, no cheaper way. currently */
3488  IMB_buffer_float_from_byte(display_buffer_float,
3489  byte_buffer,
3492  true,
3493  width,
3494  height,
3495  width,
3496  display_stride);
3497  }
3498  else {
3499  int i;
3500 
3501  for (i = ymin; i < ymax; i++) {
3502  size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
3503  size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
3504 
3505  memcpy(
3506  display_buffer + display_offset, byte_buffer + byte_offset, sizeof(char[4]) * width);
3507  }
3508  }
3509  }
3510 
3511  if (display_buffer_float) {
3512  size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
3513 
3514  IMB_buffer_byte_from_float(display_buffer + display_index,
3515  display_buffer_float,
3516  channels,
3517  dither,
3520  true,
3521  width,
3522  height,
3523  display_stride,
3524  width);
3525 
3526  MEM_freeN(display_buffer_float);
3527  }
3528 }
3529 
3530 typedef struct PartialThreadData {
3532  unsigned char *display_buffer;
3533  const float *linear_buffer;
3534  const unsigned char *byte_buffer;
3539  int xmin, ymin, xmax;
3541 
3542 static void partial_buffer_update_rect_thread_do(void *data_v,
3543  int start_scanline,
3544  int num_scanlines)
3545 {
3547  int ymin = data->ymin + start_scanline;
3549  data->display_buffer,
3550  data->linear_buffer,
3551  data->byte_buffer,
3552  data->display_stride,
3553  data->linear_stride,
3554  data->linear_offset_x,
3555  data->linear_offset_y,
3556  data->cm_processor,
3557  data->xmin,
3558  ymin,
3559  data->xmax,
3560  ymin + num_scanlines);
3561 }
3562 
3564  ImBuf *ibuf,
3565  const float *linear_buffer,
3566  const unsigned char *byte_buffer,
3567  int stride,
3568  int offset_x,
3569  int offset_y,
3570  const ColorManagedViewSettings *view_settings,
3571  const ColorManagedDisplaySettings *display_settings,
3572  int xmin,
3573  int ymin,
3574  int xmax,
3575  int ymax,
3576  bool do_threads)
3577 {
3578  ColormanageCacheViewSettings cache_view_settings;
3579  ColormanageCacheDisplaySettings cache_display_settings;
3580  void *cache_handle = NULL;
3581  unsigned char *display_buffer = NULL;
3582  int buffer_width = ibuf->x;
3583 
3584  if (ibuf->display_buffer_flags) {
3585  int view_flag, display_index;
3586 
3587  colormanage_view_settings_to_cache(ibuf, &cache_view_settings, view_settings);
3588  colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
3589 
3590  view_flag = 1 << (cache_view_settings.view - 1);
3591  display_index = cache_display_settings.display - 1;
3592 
3594 
3595  if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
3596  display_buffer = colormanage_cache_get(
3597  ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
3598  }
3599 
3600  /* In some rare cases buffer's dimension could be changing directly from
3601  * different thread
3602  * this i.e. happens when image editor acquires render result
3603  */
3604  buffer_width = ibuf->x;
3605 
3606  /* Mark all other buffers as invalid. */
3607  memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
3608  ibuf->display_buffer_flags[display_index] |= view_flag;
3609 
3611  }
3612 
3613  if (display_buffer) {
3614  ColormanageProcessor *cm_processor = NULL;
3615  bool skip_transform = false;
3616 
3617  /* Byte buffer is assumed to be in imbuf's rect space, so if byte buffer
3618  * is known we could skip display->linear->display conversion in case
3619  * display color space matches imbuf's rect space.
3620  *
3621  * But if there's a float buffer it's likely operation was performed on
3622  * it first and byte buffer is likely to be out of date here.
3623  */
3624  if (linear_buffer == NULL && byte_buffer != NULL) {
3625  skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
3626  }
3627 
3628  if (!skip_transform) {
3629  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
3630  }
3631 
3632  if (do_threads) {
3634  data.ibuf = ibuf;
3635  data.display_buffer = display_buffer;
3636  data.linear_buffer = linear_buffer;
3637  data.byte_buffer = byte_buffer;
3638  data.display_stride = buffer_width;
3639  data.linear_stride = stride;
3640  data.linear_offset_x = offset_x;
3641  data.linear_offset_y = offset_y;
3642  data.cm_processor = cm_processor;
3643  data.xmin = xmin;
3644  data.ymin = ymin;
3645  data.xmax = xmax;
3648  }
3649  else {
3651  display_buffer,
3652  linear_buffer,
3653  byte_buffer,
3654  buffer_width,
3655  stride,
3656  offset_x,
3657  offset_y,
3658  cm_processor,
3659  xmin,
3660  ymin,
3661  xmax,
3662  ymax);
3663  }
3664 
3665  if (cm_processor) {
3666  IMB_colormanagement_processor_free(cm_processor);
3667  }
3668 
3669  IMB_display_buffer_release(cache_handle);
3670  }
3671 }
3672 
3674  const float *linear_buffer,
3675  const unsigned char *byte_buffer,
3676  int stride,
3677  int offset_x,
3678  int offset_y,
3679  const ColorManagedViewSettings *view_settings,
3680  const ColorManagedDisplaySettings *display_settings,
3681  int xmin,
3682  int ymin,
3683  int xmax,
3684  int ymax)
3685 {
3687  linear_buffer,
3688  byte_buffer,
3689  stride,
3690  offset_x,
3691  offset_y,
3692  view_settings,
3693  display_settings,
3694  xmin,
3695  ymin,
3696  xmax,
3697  ymax,
3698  false);
3699 }
3700 
3702  struct ImBuf *ibuf,
3703  const float *linear_buffer,
3704  const unsigned char *byte_buffer,
3705  int stride,
3706  int offset_x,
3707  int offset_y,
3708  const struct ColorManagedViewSettings *view_settings,
3709  const struct ColorManagedDisplaySettings *display_settings,
3710  int xmin,
3711  int ymin,
3712  int xmax,
3713  int ymax)
3714 {
3715  int width = xmax - xmin;
3716  int height = ymax - ymin;
3717  bool do_threads = (((size_t)width) * height >= 64 * 64);
3719  linear_buffer,
3720  byte_buffer,
3721  stride,
3722  offset_x,
3723  offset_y,
3724  view_settings,
3725  display_settings,
3726  xmin,
3727  ymin,
3728  xmax,
3729  ymax,
3730  do_threads);
3731 }
3732 
3733 void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
3734 {
3735  if (ibuf->invalid_rect.xmin == ibuf->invalid_rect.xmax) {
3736  BLI_rcti_init(&ibuf->invalid_rect, xmin, xmax, ymin, ymax);
3737  }
3738  else {
3739  rcti rect;
3740  BLI_rcti_init(&rect, xmin, xmax, ymin, ymax);
3741  BLI_rcti_union(&ibuf->invalid_rect, &rect);
3742  }
3743 }
3744 
3747 /* -------------------------------------------------------------------- */
3752  const ColorManagedViewSettings *view_settings,
3753  const ColorManagedDisplaySettings *display_settings)
3754 {
3755  ColormanageProcessor *cm_processor;
3756  ColorManagedViewSettings default_view_settings;
3757  const ColorManagedViewSettings *applied_view_settings;
3758  ColorSpace *display_space;
3759 
3760  cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
3761 
3762  if (view_settings) {
3763  applied_view_settings = view_settings;
3764  }
3765  else {
3766  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
3767  applied_view_settings = &default_view_settings;
3768  }
3769 
3770  display_space = display_transform_get_colorspace(applied_view_settings, display_settings);
3771  if (display_space) {
3772  cm_processor->is_data_result = display_space->is_data;
3773  }
3774 
3776  applied_view_settings->look,
3777  applied_view_settings->view_transform,
3778  display_settings->display_device,
3779  applied_view_settings->exposure,
3780  applied_view_settings->gamma,
3782 
3783  if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
3784  cm_processor->curve_mapping = BKE_curvemapping_copy(applied_view_settings->curve_mapping);
3785  BKE_curvemapping_premultiply(cm_processor->curve_mapping, false);
3786  }
3787 
3788  return cm_processor;
3789 }
3790 
3792  const char *to_colorspace)
3793 {
3794  ColormanageProcessor *cm_processor;
3795  ColorSpace *color_space;
3796 
3797  cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
3798 
3799  color_space = colormanage_colorspace_get_named(to_colorspace);
3800  cm_processor->is_data_result = color_space->is_data;
3801 
3802  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(from_colorspace,
3803  to_colorspace);
3804  if (processor != NULL) {
3805  cm_processor->cpu_processor = OCIO_processorGetCPUProcessor(processor);
3806  }
3807  OCIO_processorRelease(processor);
3808 
3809  return cm_processor;
3810 }
3811 
3813 {
3814  if (cm_processor->curve_mapping) {
3815  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3816  }
3817 
3818  if (cm_processor->cpu_processor) {
3819  OCIO_cpuProcessorApplyRGBA(cm_processor->cpu_processor, pixel);
3820  }
3821 }
3822 
3824  float pixel[4])
3825 {
3826  if (cm_processor->curve_mapping) {
3827  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3828  }
3829 
3830  if (cm_processor->cpu_processor) {
3832  }
3833 }
3834 
3836 {
3837  if (cm_processor->curve_mapping) {
3838  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3839  }
3840 
3841  if (cm_processor->cpu_processor) {
3842  OCIO_cpuProcessorApplyRGB(cm_processor->cpu_processor, pixel);
3843  }
3844 }
3845 
3847  float *pixel,
3848  int channels)
3849 {
3850  if (channels == 4) {
3852  }
3853  else if (channels == 3) {
3854  IMB_colormanagement_processor_apply_v3(cm_processor, pixel);
3855  }
3856  else if (channels == 1) {
3857  if (cm_processor->curve_mapping) {
3858  curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, 1);
3859  }
3860  }
3861  else {
3862  BLI_assert(
3863  !"Incorrect number of channels passed to IMB_colormanagement_processor_apply_pixel");
3864  }
3865 }
3866 
3868  float *buffer,
3869  int width,
3870  int height,
3871  int channels,
3872  bool predivide)
3873 {
3874  /* apply curve mapping */
3875  if (cm_processor->curve_mapping) {
3876  int x, y;
3877 
3878  for (y = 0; y < height; y++) {
3879  for (x = 0; x < width; x++) {
3880  float *pixel = buffer + channels * (((size_t)y) * width + x);
3881 
3882  curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
3883  }
3884  }
3885  }
3886 
3887  if (cm_processor->cpu_processor && channels >= 3) {
3888  OCIO_PackedImageDesc *img;
3889 
3890  /* apply OCIO processor */
3892  width,
3893  height,
3894  channels,
3895  sizeof(float),
3896  (size_t)channels * sizeof(float),
3897  (size_t)channels * sizeof(float) * width);
3898 
3899  if (predivide) {
3900  OCIO_cpuProcessorApply_predivide(cm_processor->cpu_processor, img);
3901  }
3902  else {
3903  OCIO_cpuProcessorApply(cm_processor->cpu_processor, img);
3904  }
3905 
3907  }
3908 }
3909 
3911  ColormanageProcessor *cm_processor, unsigned char *buffer, int width, int height, int channels)
3912 {
3913  /* TODO(sergey): Would be nice to support arbitrary channels configurations,
3914  * but for now it's not so important.
3915  */
3916  BLI_assert(channels == 4);
3917  float pixel[4];
3918  for (int y = 0; y < height; y++) {
3919  for (int x = 0; x < width; x++) {
3920  size_t offset = channels * (((size_t)y) * width + x);
3921  rgba_uchar_to_float(pixel, buffer + offset);
3922  IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
3923  rgba_float_to_uchar(buffer + offset, pixel);
3924  }
3925  }
3926 }
3927 
3929 {
3930  if (cm_processor->curve_mapping) {
3931  BKE_curvemapping_free(cm_processor->curve_mapping);
3932  }
3933  if (cm_processor->cpu_processor) {
3934  OCIO_cpuProcessorRelease(cm_processor->cpu_processor);
3935  }
3936 
3937  MEM_freeN(cm_processor);
3938 }
3939 
3940 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
3941 
3943  OCIO_CurveMappingSettings *curve_mapping_settings)
3944 {
3945  int i;
3946 
3947  BKE_curvemapping_init(curve_mapping);
3948  BKE_curvemapping_premultiply(curve_mapping, false);
3950  curve_mapping, &curve_mapping_settings->lut, &curve_mapping_settings->lut_size);
3951 
3952  curve_mapping_settings->use_extend_extrapolate = (curve_mapping->flag &
3954 
3955  for (i = 0; i < 4; i++) {
3956  CurveMap *cuma = curve_mapping->cm + i;
3957  curve_mapping_settings->range[i] = cuma->range;
3958  curve_mapping_settings->mintable[i] = cuma->mintable;
3959  curve_mapping_settings->ext_in_x[i] = cuma->ext_in[0];
3960  curve_mapping_settings->ext_in_y[i] = cuma->ext_in[1];
3961  curve_mapping_settings->ext_out_x[i] = cuma->ext_out[0];
3962  curve_mapping_settings->ext_out_y[i] = cuma->ext_out[1];
3963  curve_mapping_settings->first_x[i] = cuma->table[0].x;
3964  curve_mapping_settings->first_y[i] = cuma->table[0].y;
3965  curve_mapping_settings->last_x[i] = cuma->table[CM_TABLE].x;
3966  curve_mapping_settings->last_y[i] = cuma->table[CM_TABLE].y;
3967  }
3968 
3969  copy_v3_v3(curve_mapping_settings->black, curve_mapping->black);
3970  copy_v3_v3(curve_mapping_settings->bwmul, curve_mapping->bwmul);
3971 
3972  curve_mapping_settings->cache_id = (size_t)curve_mapping + curve_mapping->changed_timestamp;
3973 }
3974 
3976  const ColorManagedViewSettings *view_settings)
3977 {
3978  /* Using curve mapping? */
3979  const bool use_curve_mapping = (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) != 0;
3980  if (!use_curve_mapping) {
3981  return NULL;
3982  }
3983 
3984  /* Already up to date? */
3986  if (view_settings->curve_mapping->changed_timestamp ==
3989  return curve_mapping_settings;
3990  }
3991 
3992  /* Need to update. */
3993  CurveMapping *new_curve_mapping = NULL;
3994 
3995  /* We're using curve mapping's address as a cache ID,
3996  * so we need to make sure re-allocation gives new address here.
3997  * We do this by allocating new curve mapping before freeing old one. */
3998  if (use_curve_mapping) {
3999  new_curve_mapping = BKE_curvemapping_copy(view_settings->curve_mapping);
4000  }
4001 
4004  MEM_freeN(curve_mapping_settings->lut);
4006  curve_mapping_settings->lut = NULL;
4007  }
4008 
4009  /* Fill in OCIO's curve mapping settings. */
4010  if (use_curve_mapping) {
4012 
4013  global_gpu_state.curve_mapping = new_curve_mapping;
4017  }
4018  else {
4021  }
4022 
4023  return curve_mapping_settings;
4024 }
4025 
4027 {
4028  return OCIO_supportGPUShader();
4029 }
4030 
4045  const ColorManagedViewSettings *view_settings,
4046  const ColorManagedDisplaySettings *display_settings,
4047  struct ColorSpace *from_colorspace,
4048  float dither,
4049  bool predivide,
4050  bool do_overlay_merge)
4051 {
4052  ColorManagedViewSettings default_view_settings;
4053  const ColorManagedViewSettings *applied_view_settings;
4054 
4055  if (view_settings) {
4056  applied_view_settings = view_settings;
4057  }
4058  else {
4059  /* If no view settings were specified, use default ones, which will
4060  * attempt not to do any extra color correction. */
4061  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
4062  applied_view_settings = &default_view_settings;
4063  }
4064 
4065  /* Ensure curve mapping is up to data. */
4066  OCIO_CurveMappingSettings *curve_mapping_settings = update_glsl_curve_mapping(
4067  applied_view_settings);
4068 
4069  /* GPU shader parameters. */
4070  const char *input = from_colorspace ? from_colorspace->name : global_role_scene_linear;
4071  const char *view = applied_view_settings->view_transform;
4072  const char *display = display_settings->display_device;
4073  const bool use_look = colormanage_use_look(applied_view_settings->look,
4074  applied_view_settings->view_transform);
4075  const char *look = (use_look) ? applied_view_settings->look : "";
4076  const float exposure = applied_view_settings->exposure;
4077  const float gamma = applied_view_settings->gamma;
4078  const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
4079  const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
4080 
4081  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
4082 
4083  /* Bind shader. Internally GPU shaders are created and cached on demand. */
4085  input,
4086  view,
4087  display,
4088  look,
4089  curve_mapping_settings,
4090  scale,
4091  exponent,
4092  dither,
4093  predivide,
4094  do_overlay_merge);
4095 
4096  OCIO_configRelease(config);
4097 
4099 }
4100 
4101 /* Configures GLSL shader for conversion from scene linear to display space */
4103  const ColorManagedDisplaySettings *display_settings,
4104  float dither,
4105  bool predivide)
4106 {
4108  view_settings, display_settings, NULL, dither, predivide, false);
4109 }
4110 
4116  struct ColorSpace *from_colorspace,
4117  float dither,
4118  bool predivide)
4119 {
4120  ColorManagedViewSettings *view_settings;
4121  ColorManagedDisplaySettings *display_settings;
4122 
4123  IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
4124 
4126  view_settings, display_settings, from_colorspace, dither, predivide, false);
4127 }
4128 
4129 /* Same as setup_glsl_draw, but color management settings are guessing from a given context */
4130 bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
4131 {
4132  return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
4133 }
4134 
4135 /* Finish GLSL-based display space conversion */
4137 {
4141  }
4142 }
4143 
typedef float(TangentPoint)[2]
@ BLENDER_DATAFILES
Definition: BKE_appdir.h:78
const char * BKE_appdir_folder_id(const int folder_id, const char *subfolder)
Definition: appdir.c:674
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap, float vecout[3], const float vecin[3])
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
struct CurveMapping * BKE_curvemapping_copy(const struct CurveMapping *cumap)
void BKE_curvemapping_premultiply(struct CurveMapping *cumap, int restore)
Definition: colortools.c:805
float BKE_curvemap_evaluateF(const struct CurveMapping *cumap, const struct CurveMap *cuma, float value)
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size)
void BKE_curvemapping_free(struct CurveMapping *cumap)
Definition: colortools.c:119
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
bool BKE_imtype_requires_linear_float(const char imtype)
Definition: image.c:1487
bool BKE_imtype_is_movie(const char imtype)
Definition: image.c:1443
int BKE_image_imtype_to_ftype(const char imtype, struct ImbFormatOptions *r_options)
Definition: image.c:1328
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:923
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:395
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void straight_to_premul_v4(float color[4])
void BLI_init_srgb_conversion(void)
Definition: math_color.c:606
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:414
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
Definition: math_color.c:427
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
Definition: math_color.c:407
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
Definition: math_color.c:422
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void copy_m3_m3(float m1[3][3], const float m2[3][3])
Definition: math_matrix.c:89
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1161
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define FILE_MAX
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
const char * BLI_getenv(const char *env) ATTR_NONNULL(1)
Definition: path_util.c:1313
void BLI_rcti_union(struct rcti *rct1, const struct rcti *rct2)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:446
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:666
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
void BLI_thread_unlock(int type)
Definition: threads.cc:389
void BLI_thread_lock(int type)
Definition: threads.cc:384
#define BLI_MUTEX_INITIALIZER
Definition: BLI_threads.h:84
@ LOCK_COLORMANAGE
Definition: BLI_threads.h:73
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:401
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:406
#define UNUSED(x)
#define ELEM(...)
#define STRCASEEQ(a, b)
#define STREQ(a, b)
@ CUMA_EXTEND_EXTRAPOLATE
@ COLORMANAGE_VIEW_USE_CURVES
#define CM_TABLE
@ IMA_VIEW_AS_RENDER
#define R_IMF_PLANES_RGBA
static AppView * view
_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
_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 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 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 y
_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 GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
#define BCM_CONFIG_FILE
@ COLOR_ROLE_DEFAULT_FLOAT
@ COLOR_ROLE_DATA
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
@ COLOR_ROLE_COLOR_PICKING
@ COLOR_ROLE_DEFAULT_SEQUENCER
@ COLOR_ROLE_TEXTURE_PAINTING
#define MAX_COLORSPACE_NAME
#define IM_FTYPE_FLOAT
Definition: IMB_filetype.h:29
Function declarations for filter.c.
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:478
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:720
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:115
void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_customdata, void(init_handle)(void *handle, int start_line, int tot_line, void *customdata), void *(do_thread)(void *))
Definition: imageprocess.c:362
void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:651
void IMB_buffer_float_from_byte(float *rect_to, const unsigned char *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:370
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
Definition: imageprocess.c:424
void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:112
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf)
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
Definition: imageprocess.c:455
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3])
Definition: imageprocess.c:469
bool imb_addrectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:407
Contains defines and structs used throughout the imbuf module.
@ IB_RECT_INVALID
@ IB_DISPLAY_BUFFER_INVALID
@ IMB_COLORMANAGE_IS_DATA
#define IB_PROFILE_SRGB
@ IB_alphamode_channel_packed
@ IB_alphamode_premul
@ IB_alphamode_ignore
@ IB_rectfloat
@ IB_rect
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
Definition: metadata.c:80
struct MovieCache * IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
Definition: moviecache.c:262
struct ImBuf * IMB_moviecache_get(struct MovieCache *cache, void *userkey)
Definition: moviecache.c:398
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf)
Definition: moviecache.c:364
void IMB_moviecache_free(struct MovieCache *cache)
Definition: moviecache.c:434
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
#define C
Definition: RandGen.cpp:39
#define SEQ_ALL_END
Definition: SEQ_iterator.h:48
#define SEQ_ALL_BEGIN(ed, _seq)
Definition: SEQ_iterator.h:41
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
ColorManagedColorspaceSettings colorspace_settings
const char * IMB_colormanagement_colorspace_get_indexed_name(int index)
static char global_role_data[MAX_COLORSPACE_NAME]
static void * do_processor_transform_thread(void *handle_v)
ColorManagedView * colormanage_view_get_default(const ColorManagedDisplay *display)
static ListBase global_colorspaces
static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, int height, float *linear_buffer, bool *is_straight_alpha)
void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float pixel[3], const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
unsigned char * IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, void **cache_handle)
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor, unsigned char *buffer, int width, int height, int channels)
void IMB_partial_display_buffer_update_threaded(struct ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax)
static void display_buffer_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
bool IMB_colormanagement_space_is_data(ColorSpace *colorspace)
void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *totitem)
float imbuf_luma_coefficients[3]
static void curve_mapping_to_ocio_settings(CurveMapping *curve_mapping, OCIO_CurveMappingSettings *curve_mapping_settings)
void IMB_colormanagement_processor_apply_pixel(struct ColormanageProcessor *cm_processor, float *pixel, int channels)
void colormanagement_init(void)
ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
struct ColormanageCache ColormanageCache
void colormanage_cache_free(ImBuf *ibuf)
static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
static float imbuf_xyz_to_linear_srgb[3][3]
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide)
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const struct ImBuf *ibuf, const bool compress_as_srgb, const bool store_premultiplied)
const float * IMB_colormangement_get_xyz_to_rgb()
ColorManagedView * colormanage_view_get_named_for_display(const char *display_name, const char *name)
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace)
static OCIO_ConstProcessorRcPtr * create_colorspace_transform_processor(const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4], const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool make_byte)
static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role)
bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace)
static OCIO_ConstCPUProcessorRcPtr * colorspace_to_scene_linear_cpu_processor(ColorSpace *colorspace)
void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, const char *display_name)
static unsigned char * colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, void **cache_handle)
static ColorSpace * display_transform_get_colorspace(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static char global_role_default_sequencer[MAX_COLORSPACE_NAME]
static void * do_display_buffer_apply_thread(void *handle_v)
void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, float dither, bool predivide)
static OCIO_ConstCPUProcessorRcPtr * colorspace_from_scene_linear_cpu_processor(ColorSpace *colorspace)
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name)
const char * IMB_colormanagement_view_get_default_name(const char *display_name)
ColorSpace * colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data)
static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffer, const float *linear_buffer, const unsigned char *byte_buffer, int display_stride, int linear_stride, int linear_offset_x, int linear_offset_y, ColormanageProcessor *cm_processor, const int xmin, const int ymin, const int xmax, const int ymax)
void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
struct ProcessorTransformThread ProcessorTransformThread
const char * IMB_colormanagement_get_display_colorspace_name(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
void colormanagement_exit(void)
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C, struct ColorSpace *from_colorspace, float dither, bool predivide)
static pthread_mutex_t processor_lock
static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static ColormanageCacheData * colormanage_cachedata_get(const ImBuf *ibuf)
static void imb_partial_display_buffer_update_ex(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax, bool do_threads)
struct PartialThreadData PartialThreadData
ColorManagedLook * colormanage_look_get_indexed(int index)
static struct MovieCache * colormanage_moviecache_get(const ImBuf *ibuf)
unsigned char * IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
int IMB_colormanagement_view_get_named_index(const char *name)
static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings, const char *what, const ColorManagedDisplay *default_display)
const char * colormanage_view_get_default_name(const ColorManagedDisplay *display)
void IMB_colormanagement_check_file_config(Main *bmain)
struct DisplayBufferThread DisplayBufferThread
struct ColormanageProcessor ColormanageProcessor
void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
bool IMB_colormanagement_space_name_is_data(const char *name)
static bool colormanage_hashcmp(const void *av, const void *bv)
void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
static void partial_buffer_update_rect_thread_do(void *data_v, int start_scanline, int num_scanlines)
void IMB_colormanagement_init_default_view_settings(ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static bool colormanage_use_look(const char *look, const char *view_name)
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings)
static void colormanage_ensure_srgb_scene_linear_info(ColorSpace *colorspace)
void IMB_colormanagement_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3])
static void colormanage_free_config(void)
void IMB_colormanagegent_copy_settings(ImBuf *ibuf_src, ImBuf *ibuf_dst)
void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, float *buffer, int width, int height, int channels, bool predivide)
void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
static int global_tot_view
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSED(view_settings))
static ImBuf * colormanage_cache_get_ibuf(ImBuf *ibuf, ColormanageCacheKey *key, void **cache_handle)
void IMB_display_buffer_release(void *cache_handle)
ColorManagedLook * colormanage_look_add(const char *name, const char *process_space, bool is_noop)
static void processor_transform_apply_threaded(unsigned char *byte_buffer, float *float_buffer, const int width, const int height, const int channels, ColormanageProcessor *cm_processor, const bool predivide, const bool float_from_byte)
void IMB_colormanagement_display_settings_from_ctx(const bContext *C, ColorManagedViewSettings **r_view_settings, ColorManagedDisplaySettings **r_display_settings)
ColorManagedLook * colormanage_look_get_named(const char *name)
static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
static void colormanage_cache_handle_release(void *cache_handle)
struct ColormanageCacheDisplaySettings ColormanageCacheDisplaySettings
static ListBase global_looks
static ListBase global_views
static OCIO_ConstCPUProcessorRcPtr * create_display_buffer_processor(const char *look, const char *view_transform, const char *display, float exposure, float gamma, const char *from_colorspace)
#define DISPLAY_BUFFER_CHANNELS
void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name)
const char * IMB_colormanagement_display_get_default_name(void)
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
const char * IMB_colormanagement_display_get_none_name(void)
static void colormanage_description_strip(char *description)
const char * IMB_colormanagement_view_get_indexed_name(int index)
int IMB_colormanagement_look_get_named_index(const char *name)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
ColorManagedDisplay * colormanage_display_get_named(const char *name)
float imbuf_rgb_to_xyz[3][3]
static void colormanage_display_settings_to_cache(ColormanageCacheDisplaySettings *cache_display_settings, const ColorManagedDisplaySettings *display_settings)
ColorManagedDisplay * colormanage_display_get_indexed(int index)
void colorspace_set_default_role(char *colorspace, int size, int role)
static ListBase global_displays
static bool colormanage_compatible_look(ColorManagedLook *look, const char *view_name)
bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, struct ColorSpace *from_colorspace, float dither, bool predivide, bool do_overlay_merge)
static int global_tot_display
void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
ColorManagedDisplay * colormanage_display_get_default(void)
static float imbuf_linear_srgb_to_xyz[3][3]
ColorSpace * colormanage_colorspace_get_indexed(int index)
const char * colormanage_display_get_default_name(void)
void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
struct ColormanageCacheData ColormanageCacheData
void IMB_colormanagement_finish_glsl_draw(void)
static int global_tot_colorspace
static char global_role_scene_linear[MAX_COLORSPACE_NAME]
static void colormanagement_view_item_add(EnumPropertyItem **items, int *totitem, ColorManagedView *view)
int IMB_colormanagement_colorspace_get_named_index(const char *name)
static void colormanagement_transform_ex(unsigned char *byte_buffer, float *float_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide, bool do_threaded)
void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char *display_buffer, int width, int height, int channels, float dither, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static char global_role_texture_painting[MAX_COLORSPACE_NAME]
ColorSpace * colormanage_colorspace_get_named(const char *name)
void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax)
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
static void colormanage_settings_to_key(ColormanageCacheKey *key, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings)
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
static unsigned int colormanage_hashhash(const void *key_v)
void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool predivide)
float imbuf_xyz_to_rgb[3][3]
const char * IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4])
static OCIO_CurveMappingSettings * update_glsl_curve_mapping(const ColorManagedViewSettings *view_settings)
static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, ImageFormatData *image_format_data)
static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, unsigned char *display_buffer, void **cache_handle)
const char * IMB_colormanagement_look_get_indexed_name(int index)
struct DisplayBufferInitData DisplayBufferInitData
static int global_tot_looks
ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
static OCIO_ConstCPUProcessorRcPtr * display_to_scene_linear_processor(ColorManagedDisplay *display)
struct ProcessorTransformInit ProcessorTransformInitData
struct ColormanageCacheViewSettings ColormanageCacheViewSettings
static char global_role_default_byte[MAX_COLORSPACE_NAME]
static char global_role_default_float[MAX_COLORSPACE_NAME]
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
const char * IMB_colormanagement_display_get_default_view_transform_name(struct ColorManagedDisplay *display)
void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
ColorManagedDisplay * colormanage_display_add(const char *name)
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, ColorSpace *colorspace)
const char * IMB_colormanagement_display_get_indexed_name(int index)
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
static void colormanage_view_settings_to_cache(ImBuf *ibuf, ColormanageCacheViewSettings *cache_view_settings, const ColorManagedViewSettings *view_settings)
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, float pixel[4])
int IMB_colormanagement_display_get_named_index(const char *name)
static char global_role_color_picking[MAX_COLORSPACE_NAME]
static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings, const char *what)
static void display_buffer_apply_threaded(ImBuf *ibuf, const float *buffer, unsigned char *byte_buffer, float *display_buffer, unsigned char *display_buffer_byte, ColormanageProcessor *cm_processor)
static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
struct ColormanageCacheKey ColormanageCacheKey
ColorManagedView * colormanage_view_get_named(const char *name)
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
ColorSpace * colormanage_colorspace_get_roled(int role)
ColorManagedView * colormanage_view_add(const char *name)
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const struct ImBuf *ibuf, const bool store_premultiplied)
ColorManagedView * colormanage_view_get_indexed(int index)
ColormanageProcessor * IMB_colormanagement_display_processor_new(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static OCIO_ConstCPUProcessorRcPtr * display_from_scene_linear_processor(ColorManagedDisplay *display)
static struct MovieCache * colormanage_moviecache_ensure(ImBuf *ibuf)
Scene scene
const ImFileType * IMB_file_type_from_ibuf(const ImBuf *ibuf)
Definition: filetype.c:229
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition: filter.c:669
#define powf(x, y)
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
static unsigned a[3]
Definition: RandGen.cpp:92
void OCIO_cpuProcessorApplyRGB(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition: ocio_capi.cc:218
void OCIO_cpuProcessorApplyRGBA(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition: ocio_capi.cc:223
const char * OCIO_configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display)
Definition: ocio_capi.cc:110
const char * OCIO_configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:79
OCIO_ConstCPUProcessorRcPtr * OCIO_processorGetCPUProcessor(OCIO_ConstProcessorRcPtr *processor)
Definition: ocio_capi.cc:202
OCIO_ConstConfigRcPtr * OCIO_getCurrentConfig(void)
Definition: ocio_capi.cc:41
void OCIO_lookRelease(OCIO_ConstLookRcPtr *look)
Definition: ocio_capi.cc:162
const char * OCIO_lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
Definition: ocio_capi.cc:157
void OCIO_cpuProcessorApply(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition: ocio_capi.cc:207
void OCIO_gpuCacheFree(void)
Definition: ocio_capi.cc:316
void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, OCIO_ConstColorSpaceRcPtr *cs, bool *is_scene_linear, bool *is_srgb)
Definition: ocio_capi.cc:177
void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:185
const char * OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index)
Definition: ocio_capi.cc:120
OCIO_PackedImageDesc * OCIO_createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes)
Definition: ocio_capi.cc:264
const char * OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:238
void OCIO_init(void)
Definition: ocio_capi.cc:26
const char * OCIO_configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:147
void OCIO_cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition: ocio_capi.cc:212
void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:54
OCIO_ConstConfigRcPtr * OCIO_configCreateFallback(void)
Definition: ocio_capi.cc:46
int OCIO_configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:74
void OCIO_gpuDisplayShaderUnbind(void)
Definition: ocio_capi.cc:311
void OCIO_configRelease(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:69
OCIO_ConstColorSpaceRcPtr * OCIO_configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
Definition: ocio_capi.cc:84
OCIO_ConstProcessorRcPtr * OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, const float scale, const float exponent)
Definition: ocio_capi.cc:253
int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display)
Definition: ocio_capi.cc:115
bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, OCIO_CurveMappingSettings *curve_mapping_settings, const float scale, const float exponent, const float dither, const bool use_predivide, const bool use_overlay)
Definition: ocio_capi.cc:286
const char * OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:243
void OCIO_cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
Definition: ocio_capi.cc:233
OCIO_ConstProcessorRcPtr * OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName)
Definition: ocio_capi.cc:190
void OCIO_cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *processor, float *pixel)
Definition: ocio_capi.cc:228
int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:167
void OCIO_exit(void)
Definition: ocio_capi.cc:35
OCIO_ConstConfigRcPtr * OCIO_configCreateFromEnv(void)
Definition: ocio_capi.cc:59
void OCIO_configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config, float xyz_to_rgb[3][3])
Definition: ocio_capi.cc:137
bool OCIO_supportGPUShader()
Definition: ocio_capi.cc:281
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
Definition: ocio_capi.cc:276
const char * OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view)
Definition: ocio_capi.cc:125
OCIO_ConstLookRcPtr * OCIO_configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
Definition: ocio_capi.cc:152
const char * OCIO_configGetDisplay(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:105
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:142
void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *processor)
Definition: ocio_capi.cc:197
const char * OCIO_configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:95
OCIO_ConstConfigRcPtr * OCIO_configCreateFromFile(const char *filename)
Definition: ocio_capi.cc:64
int OCIO_configGetNumDisplays(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:100
int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:172
void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
Definition: ocio_capi.cc:132
#define OCIO_ROLE_COLOR_PICKING
Definition: ocio_capi.h:36
#define OCIO_ROLE_TEXTURE_PAINT
Definition: ocio_capi.h:37
#define OCIO_ROLE_DEFAULT_FLOAT
Definition: ocio_capi.h:39
#define OCIO_ROLE_DEFAULT_SEQUENCER
Definition: ocio_capi.h:40
#define OCIO_ROLE_DEFAULT_BYTE
Definition: ocio_capi.h:38
static const float OCIO_XYZ_TO_LINEAR_SRGB[3][3]
Definition: ocio_capi.h:51
#define OCIO_ROLE_DATA
Definition: ocio_capi.h:34
#define OCIO_ROLE_SCENE_LINEAR
Definition: ocio_capi.h:35
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
struct OCIO_ConstCPUProcessorRcPtr * to_scene_linear
char name[MAX_COLORSPACE_NAME]
struct ColorManagedDisplay * next
struct OCIO_ConstCPUProcessorRcPtr * from_scene_linear
char ui_name[MAX_COLORSPACE_NAME]
char view[MAX_COLORSPACE_NAME]
struct ColorManagedLook * next
char process_space[MAX_COLORSPACE_NAME]
char name[MAX_COLORSPACE_NAME]
struct CurveMapping * curve_mapping
char name[MAX_COLORSPACE_NAME]
struct ColorSpace * next
struct OCIO_ConstCPUProcessorRcPtr * to_scene_linear
struct OCIO_ConstCPUProcessorRcPtr * from_scene_linear
char name[MAX_COLORSPACE_NAME]
char description[MAX_COLORSPACE_DESCRIPTION]
struct ColorSpace::@669 info
CurveMapping * curve_mapping
struct MovieCache * moviecache
ColormanageCacheData * data
CurveMapping * curve_mapping
OCIO_ConstCPUProcessorRcPtr * cpu_processor
CurveMapPoint * table
float mintable
float ext_out[2]
float ext_in[2]
float bwmul[3]
CurveMap cm[4]
float black[3]
ColormanageProcessor * cm_processor
unsigned char * byte_buffer
const char * float_colorspace
const char * byte_colorspace
unsigned char * display_buffer_byte
const char * byte_colorspace
ColormanageProcessor * cm_processor
const char * float_colorspace
unsigned char * byte_buffer
unsigned char * display_buffer_byte
const char * identifier
Definition: RNA_types.h:446
const char * name
Definition: RNA_types.h:450
const char * description
Definition: RNA_types.h:452
void * next
Definition: DNA_ID.h:274
rcti invalid_rect
int channels
int userflags
struct ColorSpace * rect_colorspace
ImbFormatOptions foptions
float dither
int colormanage_flag
unsigned char planes
enum eImbFileType ftype
unsigned int * rect
float * rect_float
struct ColorSpace * float_colorspace
unsigned int * display_buffer_flags
struct ColormanageCache * colormanage_cache
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase scenes
Definition: BKE_main.h:146
ListBase movieclips
Definition: BKE_main.h:177
ListBase images
Definition: BKE_main.h:154
char name[64]
Definition: moviecache.c:57
ColorManagedColorspaceSettings colorspace_settings
ColormanageProcessor * cm_processor
const unsigned char * byte_buffer
unsigned char * display_buffer
const float * linear_buffer
unsigned char * byte_buffer
ColormanageProcessor * cm_processor
ColormanageProcessor * cm_processor
ColorManagedViewSettings view_settings
struct Editing * ed
ColorManagedColorspaceSettings sequencer_colorspace_settings
ColorManagedDisplaySettings display_settings
struct Image * image
ColorManagedColorspaceSettings colorspace_settings
OCIO_ConstCPUProcessorRcPtr * cpu_processor_to
OCIO_ConstCPUProcessorRcPtr * cpu_processor_from
CurveMapping * orig_curve_mapping
OCIO_CurveMappingSettings curve_mapping_settings
CurveMapping * curve_mapping
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79