Cleanup: style, use braces for imbuf
[blender.git] / source / blender / imbuf / intern / colormanagement.c
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
20 /** \file
21  * \ingroup imbuf
22  */
23
24 #include "IMB_colormanagement.h"
25 #include "IMB_colormanagement_intern.h"
26
27 #include <string.h>
28 #include <math.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_imbuf.h"
37 #include "IMB_imbuf_types.h"
38 #include "IMB_filetype.h"
39 #include "IMB_filter.h"
40 #include "IMB_moviecache.h"
41 #include "IMB_metadata.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_string.h"
49 #include "BLI_threads.h"
50 #include "BLI_rect.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 #include "BKE_sequencer.h"
58
59 #include "RNA_define.h"
60
61 #include <ocio_capi.h>
62
63 /*********************** Global declarations *************************/
64
65 #define DISPLAY_BUFFER_CHANNELS 4
66
67 /* ** list of all supported color spaces, displays and views */
68 static char global_role_scene_linear[MAX_COLORSPACE_NAME];
69 static char global_role_color_picking[MAX_COLORSPACE_NAME];
70 static char global_role_texture_painting[MAX_COLORSPACE_NAME];
71 static char global_role_default_byte[MAX_COLORSPACE_NAME];
72 static char global_role_default_float[MAX_COLORSPACE_NAME];
73 static char global_role_default_sequencer[MAX_COLORSPACE_NAME];
74
75 static ListBase global_colorspaces = {NULL, NULL};
76 static ListBase global_displays = {NULL, NULL};
77 static ListBase global_views = {NULL, NULL};
78 static ListBase global_looks = {NULL, NULL};
79
80 static int global_tot_colorspace = 0;
81 static int global_tot_display = 0;
82 static int global_tot_view = 0;
83 static int global_tot_looks = 0;
84
85 /* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
86 float imbuf_luma_coefficients[3] = {0.0f};
87 float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
88 float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
89 static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
90 static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
91
92 /* lock used by pre-cached processors getters, so processor wouldn't
93  * be created several times
94  * LOCK_COLORMANAGE can not be used since this mutex could be needed to
95  * be locked before pre-cached processor are creating
96  */
97 static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER;
98
99 typedef struct ColormanageProcessor {
100   OCIO_ConstProcessorRcPtr *processor;
101   CurveMapping *curve_mapping;
102   bool is_data_result;
103 } ColormanageProcessor;
104
105 static struct global_glsl_state {
106   /* Actual processor used for GLSL baked LUTs. */
107   OCIO_ConstProcessorRcPtr *processor;
108
109   /* Settings of processor for comparison. */
110   char look[MAX_COLORSPACE_NAME];
111   char view[MAX_COLORSPACE_NAME];
112   char display[MAX_COLORSPACE_NAME];
113   char input[MAX_COLORSPACE_NAME];
114   float exposure, gamma;
115
116   CurveMapping *curve_mapping, *orig_curve_mapping;
117   bool use_curve_mapping;
118   int curve_mapping_timestamp;
119   OCIO_CurveMappingSettings curve_mapping_settings;
120
121   /* Container for GLSL state needed for OCIO module. */
122   struct OCIO_GLSLDrawState *ocio_glsl_state;
123   struct OCIO_GLSLDrawState *transform_ocio_glsl_state;
124 } global_glsl_state = {NULL};
125
126 static struct global_color_picking_state {
127   /* Cached processor for color picking conversion. */
128   OCIO_ConstProcessorRcPtr *processor_to;
129   OCIO_ConstProcessorRcPtr *processor_from;
130   bool failed;
131 } global_color_picking_state = {NULL};
132
133 /*********************** Color managed cache *************************/
134
135 /* Cache Implementation Notes
136  * ==========================
137  *
138  * All color management cache stuff is stored in two properties of
139  * image buffers:
140  *
141  *   1. display_buffer_flags
142  *
143  *      This is a bit field which used to mark calculated transformations
144  *      for particular image buffer. Index inside of this array means index
145  *      of a color managed display. Element with given index matches view
146  *      transformations applied for a given display. So if bit B of array
147  *      element B is set to 1, this means display buffer with display index
148  *      of A and view transform of B was ever calculated for this imbuf.
149  *
150  *      In contrast with indices in global lists of displays and views this
151  *      indices are 0-based, not 1-based. This is needed to save some bytes
152  *      of memory.
153  *
154  *   2. colormanage_cache
155  *
156  *      This is a pointer to a structure which holds all data which is
157  *      needed for color management cache to work.
158  *
159  *      It contains two parts:
160  *        - data
161  *        - moviecache
162  *
163  *      Data field is used to store additional information about cached
164  *      buffers which affects on whether cached buffer could be used.
165  *      This data can't go to cache key because changes in this data
166  *      shouldn't lead extra buffers adding to cache, it shall
167  *      invalidate cached images.
168  *
169  *      Currently such a data contains only exposure and gamma, but
170  *      would likely extended further.
171  *
172  *      data field is not null only for elements of cache, not used for
173  *      original image buffers.
174  *
175  *      Color management cache is using generic MovieCache implementation
176  *      to make it easier to deal with memory limitation.
177  *
178  *      Currently color management is using the same memory limitation
179  *      pool as sequencer and clip editor are using which means color
180  *      managed buffers would be removed from the cache as soon as new
181  *      frames are loading for the movie clip and there's no space in
182  *      cache.
183  *
184  *      Every image buffer has got own movie cache instance, which
185  *      means keys for color managed buffers could be really simple
186  *      and look up in this cache would be fast and independent from
187  *      overall amount of color managed images.
188  */
189
190 /* NOTE: ColormanageCacheViewSettings and ColormanageCacheDisplaySettings are
191  *       quite the same as ColorManagedViewSettings and ColorManageDisplaySettings
192  *       but they holds indexes of all transformations and color spaces, not
193  *       their names.
194  *
195  *       This helps avoid extra colorspace / display / view lookup without
196  *       requiring to pass all variables which affects on display buffer
197  *       to color management cache system and keeps calls small and nice.
198  */
199 typedef struct ColormanageCacheViewSettings {
200   int flag;
201   int look;
202   int view;
203   float exposure;
204   float gamma;
205   float dither;
206   CurveMapping *curve_mapping;
207 } ColormanageCacheViewSettings;
208
209 typedef struct ColormanageCacheDisplaySettings {
210   int display;
211 } ColormanageCacheDisplaySettings;
212
213 typedef struct ColormanageCacheKey {
214   int view;    /* view transformation used for display buffer */
215   int display; /* display device name */
216 } ColormanageCacheKey;
217
218 typedef struct ColormanageCacheData {
219   int flag;                    /* view flags of cached buffer */
220   int look;                    /* Additional artistics transform */
221   float exposure;              /* exposure value cached buffer is calculated with */
222   float gamma;                 /* gamma value cached buffer is calculated with */
223   float dither;                /* dither value cached buffer is calculated with */
224   CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
225   int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
226 } ColormanageCacheData;
227
228 typedef struct ColormanageCache {
229   struct MovieCache *moviecache;
230
231   ColormanageCacheData *data;
232 } ColormanageCache;
233
234 static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
235 {
236   if (!ibuf->colormanage_cache) {
237     return NULL;
238   }
239
240   return ibuf->colormanage_cache->moviecache;
241 }
242
243 static ColormanageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
244 {
245   if (!ibuf->colormanage_cache) {
246     return NULL;
247   }
248
249   return ibuf->colormanage_cache->data;
250 }
251
252 static unsigned int colormanage_hashhash(const void *key_v)
253 {
254   const ColormanageCacheKey *key = key_v;
255
256   unsigned int rval = (key->display << 16) | (key->view % 0xffff);
257
258   return rval;
259 }
260
261 static bool colormanage_hashcmp(const void *av, const void *bv)
262 {
263   const ColormanageCacheKey *a = av;
264   const ColormanageCacheKey *b = bv;
265
266   return ((a->view != b->view) || (a->display != b->display));
267 }
268
269 static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
270 {
271   if (!ibuf->colormanage_cache) {
272     ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
273   }
274
275   if (!ibuf->colormanage_cache->moviecache) {
276     struct MovieCache *moviecache;
277
278     moviecache = IMB_moviecache_create("colormanage cache",
279                                        sizeof(ColormanageCacheKey),
280                                        colormanage_hashhash,
281                                        colormanage_hashcmp);
282
283     ibuf->colormanage_cache->moviecache = moviecache;
284   }
285
286   return ibuf->colormanage_cache->moviecache;
287 }
288
289 static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
290 {
291   if (!ibuf->colormanage_cache) {
292     ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
293   }
294
295   ibuf->colormanage_cache->data = data;
296 }
297
298 static void colormanage_view_settings_to_cache(ImBuf *ibuf,
299                                                ColormanageCacheViewSettings *cache_view_settings,
300                                                const ColorManagedViewSettings *view_settings)
301 {
302   int look = IMB_colormanagement_look_get_named_index(view_settings->look);
303   int view = IMB_colormanagement_view_get_named_index(view_settings->view_transform);
304
305   cache_view_settings->look = look;
306   cache_view_settings->view = view;
307   cache_view_settings->exposure = view_settings->exposure;
308   cache_view_settings->gamma = view_settings->gamma;
309   cache_view_settings->dither = ibuf->dither;
310   cache_view_settings->flag = view_settings->flag;
311   cache_view_settings->curve_mapping = view_settings->curve_mapping;
312 }
313
314 static void colormanage_display_settings_to_cache(
315     ColormanageCacheDisplaySettings *cache_display_settings,
316     const ColorManagedDisplaySettings *display_settings)
317 {
318   int display = IMB_colormanagement_display_get_named_index(display_settings->display_device);
319
320   cache_display_settings->display = display;
321 }
322
323 static void colormanage_settings_to_key(ColormanageCacheKey *key,
324                                         const ColormanageCacheViewSettings *view_settings,
325                                         const ColormanageCacheDisplaySettings *display_settings)
326 {
327   key->view = view_settings->view;
328   key->display = display_settings->display;
329 }
330
331 static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf,
332                                          ColormanageCacheKey *key,
333                                          void **cache_handle)
334 {
335   ImBuf *cache_ibuf;
336   struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
337
338   if (!moviecache) {
339     /* If there's no moviecache it means no color management was applied
340      * on given image buffer before. */
341     return NULL;
342   }
343
344   *cache_handle = NULL;
345
346   cache_ibuf = IMB_moviecache_get(moviecache, key);
347
348   *cache_handle = cache_ibuf;
349
350   return cache_ibuf;
351 }
352
353 static unsigned char *colormanage_cache_get(
354     ImBuf *ibuf,
355     const ColormanageCacheViewSettings *view_settings,
356     const ColormanageCacheDisplaySettings *display_settings,
357     void **cache_handle)
358 {
359   ColormanageCacheKey key;
360   ImBuf *cache_ibuf;
361   int view_flag = 1 << (view_settings->view - 1);
362   CurveMapping *curve_mapping = view_settings->curve_mapping;
363   int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
364
365   colormanage_settings_to_key(&key, view_settings, display_settings);
366
367   /* check whether image was marked as dirty for requested transform */
368   if ((ibuf->display_buffer_flags[display_settings->display - 1] & view_flag) == 0) {
369     return NULL;
370   }
371
372   cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
373
374   if (cache_ibuf) {
375     ColormanageCacheData *cache_data;
376
377     BLI_assert(cache_ibuf->x == ibuf->x && cache_ibuf->y == ibuf->y);
378
379     /* only buffers with different color space conversions are being stored
380      * in cache separately. buffer which were used only different exposure/gamma
381      * are re-suing the same cached buffer
382      *
383      * check here which exposure/gamma/curve was used for cached buffer and if they're
384      * different from requested buffer should be re-generated
385      */
386     cache_data = colormanage_cachedata_get(cache_ibuf);
387
388     if (cache_data->look != view_settings->look ||
389         cache_data->exposure != view_settings->exposure ||
390         cache_data->gamma != view_settings->gamma || cache_data->dither != view_settings->dither ||
391         cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping ||
392         cache_data->curve_mapping_timestamp != curve_mapping_timestamp) {
393       *cache_handle = NULL;
394
395       IMB_freeImBuf(cache_ibuf);
396
397       return NULL;
398     }
399
400     return (unsigned char *)cache_ibuf->rect;
401   }
402
403   return NULL;
404 }
405
406 static void colormanage_cache_put(ImBuf *ibuf,
407                                   const ColormanageCacheViewSettings *view_settings,
408                                   const ColormanageCacheDisplaySettings *display_settings,
409                                   unsigned char *display_buffer,
410                                   void **cache_handle)
411 {
412   ColormanageCacheKey key;
413   ImBuf *cache_ibuf;
414   ColormanageCacheData *cache_data;
415   int view_flag = 1 << (view_settings->view - 1);
416   struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
417   CurveMapping *curve_mapping = view_settings->curve_mapping;
418   int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
419
420   colormanage_settings_to_key(&key, view_settings, display_settings);
421
422   /* mark display buffer as valid */
423   ibuf->display_buffer_flags[display_settings->display - 1] |= view_flag;
424
425   /* buffer itself */
426   cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
427   cache_ibuf->rect = (unsigned int *)display_buffer;
428
429   cache_ibuf->mall |= IB_rect;
430   cache_ibuf->flags |= IB_rect;
431
432   /* Store data which is needed to check whether cached buffer
433    * could be used for color managed display settings. */
434   cache_data = MEM_callocN(sizeof(ColormanageCacheData), "color manage cache imbuf data");
435   cache_data->look = view_settings->look;
436   cache_data->exposure = view_settings->exposure;
437   cache_data->gamma = view_settings->gamma;
438   cache_data->dither = view_settings->dither;
439   cache_data->flag = view_settings->flag;
440   cache_data->curve_mapping = curve_mapping;
441   cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
442
443   colormanage_cachedata_set(cache_ibuf, cache_data);
444
445   *cache_handle = cache_ibuf;
446
447   IMB_moviecache_put(moviecache, &key, cache_ibuf);
448 }
449
450 static void colormanage_cache_handle_release(void *cache_handle)
451 {
452   ImBuf *cache_ibuf = cache_handle;
453
454   IMB_freeImBuf(cache_ibuf);
455 }
456
457 /*********************** Initialization / De-initialization *************************/
458
459 static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
460                                                   char *colorspace_name,
461                                                   const char *role,
462                                                   const char *backup_role)
463 {
464   OCIO_ConstColorSpaceRcPtr *ociocs;
465
466   ociocs = OCIO_configGetColorSpace(config, role);
467
468   if (!ociocs && backup_role) {
469     ociocs = OCIO_configGetColorSpace(config, backup_role);
470   }
471
472   if (ociocs) {
473     const char *name = OCIO_colorSpaceGetName(ociocs);
474
475     /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
476     BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
477     OCIO_colorSpaceRelease(ociocs);
478   }
479   else {
480     printf("Color management: Error could not find role %s role.\n", role);
481   }
482 }
483
484 static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
485 {
486   int tot_colorspace, tot_display, tot_display_view, tot_looks;
487   int index, viewindex, viewindex2;
488   const char *name;
489
490   /* get roles */
491   colormanage_role_color_space_name_get(
492       config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL);
493   colormanage_role_color_space_name_get(
494       config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING, NULL);
495   colormanage_role_color_space_name_get(
496       config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT, NULL);
497   colormanage_role_color_space_name_get(
498       config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER, OCIO_ROLE_SCENE_LINEAR);
499   colormanage_role_color_space_name_get(
500       config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE, OCIO_ROLE_TEXTURE_PAINT);
501   colormanage_role_color_space_name_get(
502       config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT, OCIO_ROLE_SCENE_LINEAR);
503
504   /* load colorspaces */
505   tot_colorspace = OCIO_configGetNumColorSpaces(config);
506   for (index = 0; index < tot_colorspace; index++) {
507     OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
508     const char *description;
509     bool is_invertible, is_data;
510
511     name = OCIO_configGetColorSpaceNameByIndex(config, index);
512
513     ocio_colorspace = OCIO_configGetColorSpace(config, name);
514     description = OCIO_colorSpaceGetDescription(ocio_colorspace);
515     is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
516     is_data = OCIO_colorSpaceIsData(ocio_colorspace);
517
518     colormanage_colorspace_add(name, description, is_invertible, is_data);
519
520     OCIO_colorSpaceRelease(ocio_colorspace);
521   }
522
523   /* load displays */
524   viewindex2 = 0;
525   tot_display = OCIO_configGetNumDisplays(config);
526
527   for (index = 0; index < tot_display; index++) {
528     const char *displayname;
529     ColorManagedDisplay *display;
530
531     displayname = OCIO_configGetDisplay(config, index);
532
533     display = colormanage_display_add(displayname);
534
535     /* load views */
536     tot_display_view = OCIO_configGetNumViews(config, displayname);
537     for (viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
538       const char *viewname;
539       ColorManagedView *view;
540       LinkData *display_view;
541
542       viewname = OCIO_configGetView(config, displayname, viewindex);
543
544       /* first check if view transform with given name was already loaded */
545       view = colormanage_view_get_named(viewname);
546
547       if (!view) {
548         view = colormanage_view_add(viewname);
549       }
550
551       display_view = BLI_genericNodeN(view);
552
553       BLI_addtail(&display->views, display_view);
554     }
555   }
556
557   global_tot_display = tot_display;
558
559   /* load looks */
560   tot_looks = OCIO_configGetNumLooks(config);
561   colormanage_look_add("None", "", true);
562   for (index = 0; index < tot_looks; index++) {
563     OCIO_ConstLookRcPtr *ocio_look;
564     const char *process_space;
565
566     name = OCIO_configGetLookNameByIndex(config, index);
567     ocio_look = OCIO_configGetLook(config, name);
568     process_space = OCIO_lookGetProcessSpace(ocio_look);
569     OCIO_lookRelease(ocio_look);
570
571     colormanage_look_add(name, process_space, false);
572   }
573
574   /* Load luminance coefficients. */
575   OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
576   OCIO_configGetXYZtoRGB(config, imbuf_xyz_to_rgb);
577   invert_m3_m3(imbuf_rgb_to_xyz, imbuf_xyz_to_rgb);
578   copy_m3_m3(imbuf_xyz_to_linear_srgb, OCIO_XYZ_TO_LINEAR_SRGB);
579   invert_m3_m3(imbuf_linear_srgb_to_xyz, imbuf_xyz_to_linear_srgb);
580 }
581
582 static void colormanage_free_config(void)
583 {
584   ColorSpace *colorspace;
585   ColorManagedDisplay *display;
586
587   /* free color spaces */
588   colorspace = global_colorspaces.first;
589   while (colorspace) {
590     ColorSpace *colorspace_next = colorspace->next;
591
592     /* free precomputer processors */
593     if (colorspace->to_scene_linear) {
594       OCIO_processorRelease((OCIO_ConstProcessorRcPtr *)colorspace->to_scene_linear);
595     }
596
597     if (colorspace->from_scene_linear) {
598       OCIO_processorRelease((OCIO_ConstProcessorRcPtr *)colorspace->from_scene_linear);
599     }
600
601     /* free color space itself */
602     MEM_freeN(colorspace);
603
604     colorspace = colorspace_next;
605   }
606   BLI_listbase_clear(&global_colorspaces);
607   global_tot_colorspace = 0;
608
609   /* free displays */
610   display = global_displays.first;
611   while (display) {
612     ColorManagedDisplay *display_next = display->next;
613
614     /* free precomputer processors */
615     if (display->to_scene_linear) {
616       OCIO_processorRelease((OCIO_ConstProcessorRcPtr *)display->to_scene_linear);
617     }
618
619     if (display->from_scene_linear) {
620       OCIO_processorRelease((OCIO_ConstProcessorRcPtr *)display->from_scene_linear);
621     }
622
623     /* free list of views */
624     BLI_freelistN(&display->views);
625
626     MEM_freeN(display);
627     display = display_next;
628   }
629   BLI_listbase_clear(&global_displays);
630   global_tot_display = 0;
631
632   /* free views */
633   BLI_freelistN(&global_views);
634   global_tot_view = 0;
635
636   /* free looks */
637   BLI_freelistN(&global_looks);
638   global_tot_looks = 0;
639
640   OCIO_exit();
641 }
642
643 void colormanagement_init(void)
644 {
645   const char *ocio_env;
646   const char *configdir;
647   char configfile[FILE_MAX];
648   OCIO_ConstConfigRcPtr *config = NULL;
649
650   OCIO_init();
651
652   ocio_env = BLI_getenv("OCIO");
653
654   if (ocio_env && ocio_env[0] != '\0') {
655     config = OCIO_configCreateFromEnv();
656     if (config != NULL) {
657       printf("Color management: Using %s as a configuration file\n", ocio_env);
658     }
659   }
660
661   if (config == NULL) {
662     configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement");
663
664     if (configdir) {
665       BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
666
667 #ifdef WIN32
668       {
669         /* quite a hack to support loading configuration from path with non-acii symbols */
670
671         char short_name[256];
672         BLI_get_short_name(short_name, configfile);
673         config = OCIO_configCreateFromFile(short_name);
674       }
675 #else
676       config = OCIO_configCreateFromFile(configfile);
677 #endif
678     }
679   }
680
681   if (config == NULL) {
682     printf("Color management: using fallback mode for management\n");
683
684     config = OCIO_configCreateFallback();
685   }
686
687   if (config) {
688     OCIO_setCurrentConfig(config);
689
690     colormanage_load_config(config);
691
692     OCIO_configRelease(config);
693   }
694
695   /* If there're no valid display/views, use fallback mode. */
696   if (global_tot_display == 0 || global_tot_view == 0) {
697     printf("Color management: no displays/views in the config, using fallback mode instead\n");
698
699     /* Free old config. */
700     colormanage_free_config();
701
702     /* Initialize fallback config. */
703     config = OCIO_configCreateFallback();
704     colormanage_load_config(config);
705   }
706
707   BLI_init_srgb_conversion();
708 }
709
710 void colormanagement_exit(void)
711 {
712   if (global_glsl_state.processor) {
713     OCIO_processorRelease(global_glsl_state.processor);
714   }
715
716   if (global_glsl_state.curve_mapping) {
717     curvemapping_free(global_glsl_state.curve_mapping);
718   }
719
720   if (global_glsl_state.curve_mapping_settings.lut) {
721     MEM_freeN(global_glsl_state.curve_mapping_settings.lut);
722   }
723
724   if (global_glsl_state.ocio_glsl_state) {
725     OCIO_freeOGLState(global_glsl_state.ocio_glsl_state);
726   }
727
728   if (global_glsl_state.transform_ocio_glsl_state) {
729     OCIO_freeOGLState(global_glsl_state.transform_ocio_glsl_state);
730   }
731
732   if (global_color_picking_state.processor_to) {
733     OCIO_processorRelease(global_color_picking_state.processor_to);
734   }
735
736   if (global_color_picking_state.processor_from) {
737     OCIO_processorRelease(global_color_picking_state.processor_from);
738   }
739
740   memset(&global_glsl_state, 0, sizeof(global_glsl_state));
741   memset(&global_color_picking_state, 0, sizeof(global_color_picking_state));
742
743   colormanage_free_config();
744 }
745
746 /*********************** Internal functions *************************/
747
748 void colormanage_cache_free(ImBuf *ibuf)
749 {
750   if (ibuf->display_buffer_flags) {
751     MEM_freeN(ibuf->display_buffer_flags);
752
753     ibuf->display_buffer_flags = NULL;
754   }
755
756   if (ibuf->colormanage_cache) {
757     ColormanageCacheData *cache_data = colormanage_cachedata_get(ibuf);
758     struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
759
760     if (cache_data) {
761       MEM_freeN(cache_data);
762     }
763
764     if (moviecache) {
765       IMB_moviecache_free(moviecache);
766     }
767
768     MEM_freeN(ibuf->colormanage_cache);
769
770     ibuf->colormanage_cache = NULL;
771   }
772 }
773
774 void IMB_colormanagement_display_settings_from_ctx(
775     const bContext *C,
776     ColorManagedViewSettings **view_settings_r,
777     ColorManagedDisplaySettings **display_settings_r)
778 {
779   Scene *scene = CTX_data_scene(C);
780   SpaceImage *sima = CTX_wm_space_image(C);
781
782   *view_settings_r = &scene->view_settings;
783   *display_settings_r = &scene->display_settings;
784
785   if (sima && sima->image) {
786     if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0) {
787       *view_settings_r = NULL;
788     }
789   }
790 }
791
792 const char *IMB_colormanagement_get_display_colorspace_name(
793     const ColorManagedViewSettings *view_settings,
794     const ColorManagedDisplaySettings *display_settings)
795 {
796   OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
797
798   const char *display = display_settings->display_device;
799   const char *view = view_settings->view_transform;
800   const char *colorspace_name;
801
802   colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view);
803
804   OCIO_configRelease(config);
805
806   return colorspace_name;
807 }
808
809 static ColorSpace *display_transform_get_colorspace(
810     const ColorManagedViewSettings *view_settings,
811     const ColorManagedDisplaySettings *display_settings)
812 {
813   const char *colorspace_name = IMB_colormanagement_get_display_colorspace_name(view_settings,
814                                                                                 display_settings);
815
816   if (colorspace_name) {
817     return colormanage_colorspace_get_named(colorspace_name);
818   }
819
820   return NULL;
821 }
822
823 static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *look,
824                                                                  const char *view_transform,
825                                                                  const char *display,
826                                                                  float exposure,
827                                                                  float gamma,
828                                                                  const char *from_colorspace)
829 {
830   OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
831   OCIO_DisplayTransformRcPtr *dt;
832   OCIO_ConstProcessorRcPtr *processor;
833   ColorManagedLook *look_descr = colormanage_look_get_named(look);
834
835   dt = OCIO_createDisplayTransform();
836
837   OCIO_displayTransformSetInputColorSpaceName(dt, from_colorspace);
838   OCIO_displayTransformSetView(dt, view_transform);
839   OCIO_displayTransformSetDisplay(dt, display);
840
841   if (look_descr->is_noop == false) {
842     OCIO_displayTransformSetLooksOverrideEnabled(dt, true);
843     OCIO_displayTransformSetLooksOverride(dt, look);
844   }
845
846   /* fstop exposure control */
847   if (exposure != 0.0f) {
848     OCIO_MatrixTransformRcPtr *mt;
849     float gain = powf(2.0f, exposure);
850     const float scale4f[] = {gain, gain, gain, 1.0f};
851     float m44[16], offset4[4];
852
853     OCIO_matrixTransformScale(m44, offset4, scale4f);
854     mt = OCIO_createMatrixTransform();
855     OCIO_matrixTransformSetValue(mt, m44, offset4);
856     OCIO_displayTransformSetLinearCC(dt, (OCIO_ConstTransformRcPtr *)mt);
857
858     OCIO_matrixTransformRelease(mt);
859   }
860
861   /* post-display gamma transform */
862   if (gamma != 1.0f) {
863     OCIO_ExponentTransformRcPtr *et;
864     float exponent = 1.0f / MAX2(FLT_EPSILON, gamma);
865     const float exponent4f[] = {exponent, exponent, exponent, exponent};
866
867     et = OCIO_createExponentTransform();
868     OCIO_exponentTransformSetValue(et, exponent4f);
869     OCIO_displayTransformSetDisplayCC(dt, (OCIO_ConstTransformRcPtr *)et);
870
871     OCIO_exponentTransformRelease(et);
872   }
873
874   processor = OCIO_configGetProcessor(config, (OCIO_ConstTransformRcPtr *)dt);
875
876   OCIO_displayTransformRelease(dt);
877   OCIO_configRelease(config);
878
879   return processor;
880 }
881
882 static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
883                                                                        const char *to_colorspace)
884 {
885   OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
886   OCIO_ConstProcessorRcPtr *processor;
887
888   processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
889
890   OCIO_configRelease(config);
891
892   return processor;
893 }
894
895 static OCIO_ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace)
896 {
897   if (colorspace->to_scene_linear == NULL) {
898     BLI_mutex_lock(&processor_lock);
899
900     if (colorspace->to_scene_linear == NULL) {
901       OCIO_ConstProcessorRcPtr *to_scene_linear;
902       to_scene_linear = create_colorspace_transform_processor(colorspace->name,
903                                                               global_role_scene_linear);
904       colorspace->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *)to_scene_linear;
905     }
906
907     BLI_mutex_unlock(&processor_lock);
908   }
909
910   return (OCIO_ConstProcessorRcPtr *)colorspace->to_scene_linear;
911 }
912
913 static OCIO_ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace)
914 {
915   if (colorspace->from_scene_linear == NULL) {
916     BLI_mutex_lock(&processor_lock);
917
918     if (colorspace->from_scene_linear == NULL) {
919       OCIO_ConstProcessorRcPtr *from_scene_linear;
920       from_scene_linear = create_colorspace_transform_processor(global_role_scene_linear,
921                                                                 colorspace->name);
922       colorspace->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *)from_scene_linear;
923     }
924
925     BLI_mutex_unlock(&processor_lock);
926   }
927
928   return (OCIO_ConstProcessorRcPtr *)colorspace->from_scene_linear;
929 }
930
931 static OCIO_ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display)
932 {
933   if (display->from_scene_linear == NULL) {
934     BLI_mutex_lock(&processor_lock);
935
936     if (display->from_scene_linear == NULL) {
937       const char *view_name = colormanage_view_get_default_name(display);
938       OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
939       OCIO_ConstProcessorRcPtr *processor = NULL;
940
941       if (view_name && config) {
942         const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(
943             config, display->name, view_name);
944         processor = OCIO_configGetProcessorWithNames(
945             config, global_role_scene_linear, view_colorspace);
946
947         OCIO_configRelease(config);
948       }
949
950       display->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *)processor;
951     }
952
953     BLI_mutex_unlock(&processor_lock);
954   }
955
956   return (OCIO_ConstProcessorRcPtr *)display->from_scene_linear;
957 }
958
959 static OCIO_ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display)
960 {
961   if (display->to_scene_linear == NULL) {
962     BLI_mutex_lock(&processor_lock);
963
964     if (display->to_scene_linear == NULL) {
965       const char *view_name = colormanage_view_get_default_name(display);
966       OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
967       OCIO_ConstProcessorRcPtr *processor = NULL;
968
969       if (view_name && config) {
970         const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(
971             config, display->name, view_name);
972         processor = OCIO_configGetProcessorWithNames(
973             config, view_colorspace, global_role_scene_linear);
974
975         OCIO_configRelease(config);
976       }
977
978       display->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *)processor;
979     }
980
981     BLI_mutex_unlock(&processor_lock);
982   }
983
984   return (OCIO_ConstProcessorRcPtr *)display->to_scene_linear;
985 }
986
987 void IMB_colormanagement_init_default_view_settings(
988     ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
989 {
990   /* First, try use "Default" view transform of the requested device. */
991   ColorManagedView *default_view = colormanage_view_get_named_for_display(
992       display_settings->display_device, "Default");
993   /* If that fails, we fall back to the default view transform of the display
994    * as per OCIO configuration. */
995   if (default_view == NULL) {
996     ColorManagedDisplay *display = colormanage_display_get_named(display_settings->display_device);
997     if (display != NULL) {
998       default_view = colormanage_view_get_default(display);
999     }
1000   }
1001   if (default_view != NULL) {
1002     BLI_strncpy(
1003         view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1004   }
1005   else {
1006     view_settings->view_transform[0] = '\0';
1007   }
1008   /* TODO(sergey): Find a way to safely/reliable un-hardcode this. */
1009   BLI_strncpy(view_settings->look, "None", sizeof(view_settings->look));
1010   /* Initialize rest of the settings. */
1011   view_settings->flag = 0;
1012   view_settings->gamma = 1.0f;
1013   view_settings->exposure = 0.0f;
1014   view_settings->curve_mapping = NULL;
1015 }
1016
1017 static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
1018 {
1019   if (channels == 1) {
1020     pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
1021   }
1022   else if (channels == 2) {
1023     pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
1024     pixel[1] = curvemap_evaluateF(curve_mapping->cm, pixel[1]);
1025   }
1026   else {
1027     curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
1028   }
1029 }
1030
1031 void colorspace_set_default_role(char *colorspace, int size, int role)
1032 {
1033   if (colorspace && colorspace[0] == '\0') {
1034     const char *role_colorspace;
1035
1036     role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
1037
1038     BLI_strncpy(colorspace, role_colorspace, size);
1039   }
1040 }
1041
1042 void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
1043 {
1044   ibuf->rect_colorspace = colormanage_colorspace_get_named(global_role_default_byte);
1045 }
1046
1047 void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
1048 {
1049   ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace);
1050
1051   if (colorspace && colorspace->is_data) {
1052     ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1053     return;
1054   }
1055
1056   if (ibuf->rect_float) {
1057     const char *to_colorspace = global_role_scene_linear;
1058
1059     if (ibuf->rect) {
1060       imb_freerectImBuf(ibuf);
1061     }
1062
1063     IMB_colormanagement_transform(
1064         ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
1065   }
1066 }
1067
1068 /*********************** Generic functions *************************/
1069
1070 static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings,
1071                                                const char *what,
1072                                                const ColorManagedDisplay *default_display)
1073 {
1074   if (display_settings->display_device[0] == '\0') {
1075     BLI_strncpy(display_settings->display_device,
1076                 default_display->name,
1077                 sizeof(display_settings->display_device));
1078   }
1079   else {
1080     ColorManagedDisplay *display = colormanage_display_get_named(display_settings->display_device);
1081
1082     if (!display) {
1083       printf(
1084           "Color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
1085           display_settings->display_device,
1086           what,
1087           default_display->name);
1088
1089       BLI_strncpy(display_settings->display_device,
1090                   default_display->name,
1091                   sizeof(display_settings->display_device));
1092     }
1093   }
1094 }
1095
1096 static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings,
1097                                             ColorManagedViewSettings *view_settings,
1098                                             const char *what)
1099 {
1100   ColorManagedDisplay *display;
1101   ColorManagedView *default_view = NULL;
1102   ColorManagedLook *default_look = (ColorManagedLook *)global_looks.first;
1103
1104   if (view_settings->view_transform[0] == '\0') {
1105     display = colormanage_display_get_named(display_settings->display_device);
1106
1107     if (display) {
1108       default_view = colormanage_view_get_default(display);
1109     }
1110
1111     if (default_view) {
1112       BLI_strncpy(view_settings->view_transform,
1113                   default_view->name,
1114                   sizeof(view_settings->view_transform));
1115     }
1116   }
1117   else {
1118     ColorManagedView *view = colormanage_view_get_named(view_settings->view_transform);
1119
1120     if (!view) {
1121       display = colormanage_display_get_named(display_settings->display_device);
1122
1123       if (display) {
1124         default_view = colormanage_view_get_default(display);
1125       }
1126
1127       if (default_view) {
1128         printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
1129                what,
1130                view_settings->view_transform,
1131                default_view->name);
1132
1133         BLI_strncpy(view_settings->view_transform,
1134                     default_view->name,
1135                     sizeof(view_settings->view_transform));
1136       }
1137     }
1138   }
1139
1140   if (view_settings->look[0] == '\0') {
1141     BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1142   }
1143   else {
1144     ColorManagedLook *look = colormanage_look_get_named(view_settings->look);
1145     if (look == NULL) {
1146       printf("Color management: %s look \"%s\" not found, setting default \"%s\".\n",
1147              what,
1148              view_settings->look,
1149              default_look->name);
1150
1151       BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1152     }
1153   }
1154
1155   /* OCIO_TODO: move to do_versions() */
1156   if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
1157     view_settings->exposure = 0.0f;
1158     view_settings->gamma = 1.0f;
1159   }
1160 }
1161
1162 static void colormanage_check_colorspace_settings(
1163     ColorManagedColorspaceSettings *colorspace_settings, const char *what)
1164 {
1165   if (colorspace_settings->name[0] == '\0') {
1166     /* pass */
1167   }
1168   else {
1169     ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
1170
1171     if (!colorspace) {
1172       printf("Color management: %s colorspace \"%s\" not found, will use default instead.\n",
1173              what,
1174              colorspace_settings->name);
1175
1176       BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
1177     }
1178   }
1179
1180   (void)what;
1181 }
1182
1183 void IMB_colormanagement_check_file_config(Main *bmain)
1184 {
1185   Scene *scene;
1186   Image *image;
1187   MovieClip *clip;
1188
1189   ColorManagedDisplay *default_display;
1190
1191   default_display = colormanage_display_get_default();
1192
1193   if (!default_display) {
1194     /* happens when OCIO configuration is incorrect */
1195     return;
1196   }
1197
1198   for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
1199     ColorManagedColorspaceSettings *sequencer_colorspace_settings;
1200
1201     /* check scene color management settings */
1202     colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
1203     colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
1204
1205     sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
1206
1207     colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
1208
1209     if (sequencer_colorspace_settings->name[0] == '\0') {
1210       BLI_strncpy(
1211           sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
1212     }
1213
1214     /* check sequencer strip input color space settings */
1215     Sequence *seq;
1216     SEQ_BEGIN (scene->ed, seq) {
1217       if (seq->strip) {
1218         colormanage_check_colorspace_settings(&seq->strip->colorspace_settings, "sequencer strip");
1219       }
1220     }
1221     SEQ_END;
1222   }
1223
1224   /* ** check input color space settings ** */
1225
1226   for (image = bmain->images.first; image; image = image->id.next) {
1227     colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
1228   }
1229
1230   for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
1231     colormanage_check_colorspace_settings(&clip->colorspace_settings, "clip");
1232   }
1233 }
1234
1235 void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *display_settings,
1236                                            ColorManagedViewSettings *view_settings)
1237 {
1238   ColorManagedDisplay *display;
1239   ColorManagedView *default_view = NULL;
1240   LinkData *view_link;
1241
1242   display = colormanage_display_get_named(display_settings->display_device);
1243
1244   default_view = colormanage_view_get_default(display);
1245
1246   for (view_link = display->views.first; view_link; view_link = view_link->next) {
1247     ColorManagedView *view = view_link->data;
1248
1249     if (STREQ(view->name, view_settings->view_transform)) {
1250       break;
1251     }
1252   }
1253
1254   if (view_link == NULL && default_view) {
1255     BLI_strncpy(
1256         view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1257   }
1258 }
1259
1260 const char *IMB_colormanagement_role_colorspace_name_get(int role)
1261 {
1262   switch (role) {
1263     case COLOR_ROLE_SCENE_LINEAR:
1264       return global_role_scene_linear;
1265     case COLOR_ROLE_COLOR_PICKING:
1266       return global_role_color_picking;
1267     case COLOR_ROLE_TEXTURE_PAINTING:
1268       return global_role_texture_painting;
1269     case COLOR_ROLE_DEFAULT_SEQUENCER:
1270       return global_role_default_sequencer;
1271     case COLOR_ROLE_DEFAULT_FLOAT:
1272       return global_role_default_float;
1273     case COLOR_ROLE_DEFAULT_BYTE:
1274       return global_role_default_byte;
1275     default:
1276       printf("Unknown role was passed to %s\n", __func__);
1277       BLI_assert(0);
1278       break;
1279   }
1280
1281   return NULL;
1282 }
1283
1284 void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
1285 {
1286   ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1287
1288   if (colorspace && colorspace->is_data) {
1289     ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1290   }
1291   else {
1292     ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1293   }
1294 }
1295
1296 void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
1297 {
1298   ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1299
1300   ibuf->float_colorspace = colorspace;
1301
1302   if (colorspace && colorspace->is_data) {
1303     ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1304   }
1305   else {
1306     ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1307   }
1308 }
1309
1310 void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name)
1311 {
1312   ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1313
1314   ibuf->rect_colorspace = colorspace;
1315
1316   if (colorspace && colorspace->is_data) {
1317     ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1318   }
1319   else {
1320     ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1321   }
1322 }
1323
1324 const char *IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
1325 {
1326   if (ibuf->float_colorspace) {
1327     return ibuf->float_colorspace->name;
1328   }
1329   else {
1330     return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
1331   }
1332 }
1333
1334 const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
1335 {
1336   if (ibuf->rect_colorspace) {
1337     return ibuf->rect_colorspace->name;
1338   }
1339   else {
1340     return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
1341   }
1342 }
1343
1344 /*********************** Threaded display buffer transform routines *************************/
1345
1346 typedef struct DisplayBufferThread {
1347   ColormanageProcessor *cm_processor;
1348
1349   const float *buffer;
1350   unsigned char *byte_buffer;
1351
1352   float *display_buffer;
1353   unsigned char *display_buffer_byte;
1354
1355   int width;
1356   int start_line;
1357   int tot_line;
1358
1359   int channels;
1360   float dither;
1361   bool is_data;
1362
1363   const char *byte_colorspace;
1364   const char *float_colorspace;
1365 } DisplayBufferThread;
1366
1367 typedef struct DisplayBufferInitData {
1368   ImBuf *ibuf;
1369   ColormanageProcessor *cm_processor;
1370   const float *buffer;
1371   unsigned char *byte_buffer;
1372
1373   float *display_buffer;
1374   unsigned char *display_buffer_byte;
1375
1376   int width;
1377
1378   const char *byte_colorspace;
1379   const char *float_colorspace;
1380 } DisplayBufferInitData;
1381
1382 static void display_buffer_init_handle(void *handle_v,
1383                                        int start_line,
1384                                        int tot_line,
1385                                        void *init_data_v)
1386 {
1387   DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1388   DisplayBufferInitData *init_data = (DisplayBufferInitData *)init_data_v;
1389   ImBuf *ibuf = init_data->ibuf;
1390
1391   int channels = ibuf->channels;
1392   float dither = ibuf->dither;
1393   bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
1394
1395   size_t offset = ((size_t)channels) * start_line * ibuf->x;
1396   size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
1397
1398   memset(handle, 0, sizeof(DisplayBufferThread));
1399
1400   handle->cm_processor = init_data->cm_processor;
1401
1402   if (init_data->buffer) {
1403     handle->buffer = init_data->buffer + offset;
1404   }
1405
1406   if (init_data->byte_buffer) {
1407     handle->byte_buffer = init_data->byte_buffer + offset;
1408   }
1409
1410   if (init_data->display_buffer) {
1411     handle->display_buffer = init_data->display_buffer + offset;
1412   }
1413
1414   if (init_data->display_buffer_byte) {
1415     handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
1416   }
1417
1418   handle->width = ibuf->x;
1419
1420   handle->start_line = start_line;
1421   handle->tot_line = tot_line;
1422
1423   handle->channels = channels;
1424   handle->dither = dither;
1425   handle->is_data = is_data;
1426
1427   handle->byte_colorspace = init_data->byte_colorspace;
1428   handle->float_colorspace = init_data->float_colorspace;
1429 }
1430
1431 static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
1432                                                    int height,
1433                                                    float *linear_buffer,
1434                                                    bool *is_straight_alpha)
1435 {
1436   int channels = handle->channels;
1437   int width = handle->width;
1438
1439   size_t buffer_size = ((size_t)channels) * width * height;
1440
1441   bool is_data = handle->is_data;
1442   bool is_data_display = handle->cm_processor->is_data_result;
1443
1444   if (!handle->buffer) {
1445     unsigned char *byte_buffer = handle->byte_buffer;
1446
1447     const char *from_colorspace = handle->byte_colorspace;
1448     const char *to_colorspace = global_role_scene_linear;
1449
1450     float *fp;
1451     unsigned char *cp;
1452     const size_t i_last = ((size_t)width) * height;
1453     size_t i;
1454
1455     /* first convert byte buffer to float, keep in image space */
1456     for (i = 0, fp = linear_buffer, cp = byte_buffer; i != i_last;
1457          i++, fp += channels, cp += channels) {
1458       if (channels == 3) {
1459         rgb_uchar_to_float(fp, cp);
1460       }
1461       else if (channels == 4) {
1462         rgba_uchar_to_float(fp, cp);
1463       }
1464       else {
1465         BLI_assert(!"Buffers of 3 or 4 channels are only supported here");
1466       }
1467     }
1468
1469     if (!is_data && !is_data_display) {
1470       /* convert float buffer to scene linear space */
1471       IMB_colormanagement_transform(
1472           linear_buffer, width, height, channels, from_colorspace, to_colorspace, false);
1473     }
1474
1475     *is_straight_alpha = true;
1476   }
1477   else if (handle->float_colorspace) {
1478     /* currently float is non-linear only in sequencer, which is working
1479      * in it's own color space even to handle float buffers.
1480      * This color space is the same for byte and float images.
1481      * Need to convert float buffer to linear space before applying display transform
1482      */
1483
1484     const char *from_colorspace = handle->float_colorspace;
1485     const char *to_colorspace = global_role_scene_linear;
1486
1487     memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1488
1489     if (!is_data && !is_data_display) {
1490       IMB_colormanagement_transform(
1491           linear_buffer, width, height, channels, from_colorspace, to_colorspace, true);
1492     }
1493
1494     *is_straight_alpha = false;
1495   }
1496   else {
1497     /* some processors would want to modify float original buffer
1498      * before converting it into display byte buffer, so we need to
1499      * make sure original's ImBuf buffers wouldn't be modified by
1500      * using duplicated buffer here
1501      */
1502
1503     memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1504
1505     *is_straight_alpha = false;
1506   }
1507 }
1508
1509 static void *do_display_buffer_apply_thread(void *handle_v)
1510 {
1511   DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1512   ColormanageProcessor *cm_processor = handle->cm_processor;
1513   float *display_buffer = handle->display_buffer;
1514   unsigned char *display_buffer_byte = handle->display_buffer_byte;
1515   int channels = handle->channels;
1516   int width = handle->width;
1517   int height = handle->tot_line;
1518   float dither = handle->dither;
1519   bool is_data = handle->is_data;
1520
1521   if (cm_processor == NULL) {
1522     if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
1523       IMB_buffer_byte_from_byte(display_buffer_byte,
1524                                 handle->byte_buffer,
1525                                 IB_PROFILE_SRGB,
1526                                 IB_PROFILE_SRGB,
1527                                 false,
1528                                 width,
1529                                 height,
1530                                 width,
1531                                 width);
1532     }
1533
1534     if (display_buffer) {
1535       IMB_buffer_float_from_byte(display_buffer,
1536                                  handle->byte_buffer,
1537                                  IB_PROFILE_SRGB,
1538                                  IB_PROFILE_SRGB,
1539                                  false,
1540                                  width,
1541                                  height,
1542                                  width,
1543                                  width);
1544     }
1545   }
1546   else {
1547     bool is_straight_alpha, predivide;
1548     float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
1549                                        "color conversion linear buffer");
1550
1551     display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
1552
1553     predivide = is_straight_alpha == false;
1554
1555     if (is_data) {
1556       /* special case for data buffers - no color space conversions,
1557        * only generate byte buffers
1558        */
1559     }
1560     else {
1561       /* apply processor */
1562       IMB_colormanagement_processor_apply(
1563           cm_processor, linear_buffer, width, height, channels, predivide);
1564     }
1565
1566     /* copy result to output buffers */
1567     if (display_buffer_byte) {
1568       /* do conversion */
1569       IMB_buffer_byte_from_float(display_buffer_byte,
1570                                  linear_buffer,
1571                                  channels,
1572                                  dither,
1573                                  IB_PROFILE_SRGB,
1574                                  IB_PROFILE_SRGB,
1575                                  predivide,
1576                                  width,
1577                                  height,
1578                                  width,
1579                                  width);
1580     }
1581
1582     if (display_buffer) {
1583       memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
1584
1585       if (is_straight_alpha && channels == 4) {
1586         const size_t i_last = ((size_t)width) * height;
1587         size_t i;
1588         float *fp;
1589
1590         for (i = 0, fp = display_buffer; i != i_last; i++, fp += channels) {
1591           straight_to_premul_v4(fp);
1592         }
1593       }
1594     }
1595
1596     MEM_freeN(linear_buffer);
1597   }
1598
1599   return NULL;
1600 }
1601
1602 static void display_buffer_apply_threaded(ImBuf *ibuf,
1603                                           float *buffer,
1604                                           unsigned char *byte_buffer,
1605                                           float *display_buffer,
1606                                           unsigned char *display_buffer_byte,
1607                                           ColormanageProcessor *cm_processor)
1608 {
1609   DisplayBufferInitData init_data;
1610
1611   init_data.ibuf = ibuf;
1612   init_data.cm_processor = cm_processor;
1613   init_data.buffer = buffer;
1614   init_data.byte_buffer = byte_buffer;
1615   init_data.display_buffer = display_buffer;
1616   init_data.display_buffer_byte = display_buffer_byte;
1617
1618   if (ibuf->rect_colorspace != NULL) {
1619     init_data.byte_colorspace = ibuf->rect_colorspace->name;
1620   }
1621   else {
1622     /* happens for viewer images, which are not so simple to determine where to
1623      * set image buffer's color spaces
1624      */
1625     init_data.byte_colorspace = global_role_default_byte;
1626   }
1627
1628   if (ibuf->float_colorspace != NULL) {
1629     /* sequencer stores float buffers in non-linear space */
1630     init_data.float_colorspace = ibuf->float_colorspace->name;
1631   }
1632   else {
1633     init_data.float_colorspace = NULL;
1634   }
1635
1636   IMB_processor_apply_threaded(ibuf->y,
1637                                sizeof(DisplayBufferThread),
1638                                &init_data,
1639                                display_buffer_init_handle,
1640                                do_display_buffer_apply_thread);
1641 }
1642
1643 static bool is_ibuf_rect_in_display_space(ImBuf *ibuf,
1644                                           const ColorManagedViewSettings *view_settings,
1645                                           const ColorManagedDisplaySettings *display_settings)
1646 {
1647   if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) == 0 &&
1648       view_settings->exposure == 0.0f && view_settings->gamma == 1.0f) {
1649     const char *from_colorspace = ibuf->rect_colorspace->name;
1650     const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings,
1651                                                                                 display_settings);
1652     ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look);
1653     if (look_descr != NULL && !STREQ(look_descr->process_space, "")) {
1654       return false;
1655     }
1656
1657     if (to_colorspace && STREQ(from_colorspace, to_colorspace)) {
1658       return true;
1659     }
1660   }
1661
1662   return false;
1663 }
1664
1665 static void colormanage_display_buffer_process_ex(
1666     ImBuf *ibuf,
1667     float *display_buffer,
1668     unsigned char *display_buffer_byte,
1669     const ColorManagedViewSettings *view_settings,
1670     const ColorManagedDisplaySettings *display_settings)
1671 {
1672   ColormanageProcessor *cm_processor = NULL;
1673   bool skip_transform = false;
1674
1675   /* if we're going to transform byte buffer, check whether transformation would
1676    * happen to the same color space as byte buffer itself is
1677    * this would save byte -> float -> byte conversions making display buffer
1678    * computation noticeable faster
1679    */
1680   if (ibuf->rect_float == NULL && ibuf->rect_colorspace) {
1681     skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
1682   }
1683
1684   if (skip_transform == false) {
1685     cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1686   }
1687
1688   display_buffer_apply_threaded(ibuf,
1689                                 ibuf->rect_float,
1690                                 (unsigned char *)ibuf->rect,
1691                                 display_buffer,
1692                                 display_buffer_byte,
1693                                 cm_processor);
1694
1695   if (cm_processor) {
1696     IMB_colormanagement_processor_free(cm_processor);
1697   }
1698 }
1699
1700 static void colormanage_display_buffer_process(ImBuf *ibuf,
1701                                                unsigned char *display_buffer,
1702                                                const ColorManagedViewSettings *view_settings,
1703                                                const ColorManagedDisplaySettings *display_settings)
1704 {
1705   colormanage_display_buffer_process_ex(
1706       ibuf, NULL, display_buffer, view_settings, display_settings);
1707 }
1708
1709 /*********************** Threaded processor transform routines *************************/
1710
1711 typedef struct ProcessorTransformThread {
1712   ColormanageProcessor *cm_processor;
1713   unsigned char *byte_buffer;
1714   float *float_buffer;
1715   int width;
1716   int start_line;
1717   int tot_line;
1718   int channels;
1719   bool predivide;
1720   bool float_from_byte;
1721 } ProcessorTransformThread;
1722
1723 typedef struct ProcessorTransformInit {
1724   ColormanageProcessor *cm_processor;
1725   unsigned char *byte_buffer;
1726   float *float_buffer;
1727   int width;
1728   int height;
1729   int channels;
1730   bool predivide;
1731   bool float_from_byte;
1732 } ProcessorTransformInitData;
1733
1734 static void processor_transform_init_handle(void *handle_v,
1735                                             int start_line,
1736                                             int tot_line,
1737                                             void *init_data_v)
1738 {
1739   ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1740   ProcessorTransformInitData *init_data = (ProcessorTransformInitData *)init_data_v;
1741
1742   const int channels = init_data->channels;
1743   const int width = init_data->width;
1744   const bool predivide = init_data->predivide;
1745   const bool float_from_byte = init_data->float_from_byte;
1746
1747   const size_t offset = ((size_t)channels) * start_line * width;
1748
1749   memset(handle, 0, sizeof(ProcessorTransformThread));
1750
1751   handle->cm_processor = init_data->cm_processor;
1752
1753   if (init_data->byte_buffer != NULL) {
1754     /* TODO(serge): Offset might be different for byte and float buffers. */
1755     handle->byte_buffer = init_data->byte_buffer + offset;
1756   }
1757   if (init_data->float_buffer != NULL) {
1758     handle->float_buffer = init_data->float_buffer + offset;
1759   }
1760
1761   handle->width = width;
1762
1763   handle->start_line = start_line;
1764   handle->tot_line = tot_line;
1765
1766   handle->channels = channels;
1767   handle->predivide = predivide;
1768   handle->float_from_byte = float_from_byte;
1769 }
1770
1771 static void *do_processor_transform_thread(void *handle_v)
1772 {
1773   ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1774   unsigned char *byte_buffer = handle->byte_buffer;
1775   float *float_buffer = handle->float_buffer;
1776   const int channels = handle->channels;
1777   const int width = handle->width;
1778   const int height = handle->tot_line;
1779   const bool predivide = handle->predivide;
1780   const bool float_from_byte = handle->float_from_byte;
1781
1782   if (float_from_byte) {
1783     IMB_buffer_float_from_byte(float_buffer,
1784                                byte_buffer,
1785                                IB_PROFILE_SRGB,
1786                                IB_PROFILE_SRGB,
1787                                false,
1788                                width,
1789                                height,
1790                                width,
1791                                width);
1792     IMB_colormanagement_processor_apply(
1793         handle->cm_processor, float_buffer, width, height, channels, predivide);
1794     IMB_premultiply_rect_float(float_buffer, 4, width, height);
1795   }
1796   else {
1797     if (byte_buffer != NULL) {
1798       IMB_colormanagement_processor_apply_byte(
1799           handle->cm_processor, byte_buffer, width, height, channels);
1800     }
1801     if (float_buffer != NULL) {
1802       IMB_colormanagement_processor_apply(
1803           handle->cm_processor, float_buffer, width, height, channels, predivide);
1804     }
1805   }
1806
1807   return NULL;
1808 }
1809
1810 static void processor_transform_apply_threaded(unsigned char *byte_buffer,
1811                                                float *float_buffer,
1812                                                const int width,
1813                                                const int height,
1814                                                const int channels,
1815                                                ColormanageProcessor *cm_processor,
1816                                                const bool predivide,
1817                                                const bool float_from_byte)
1818 {
1819   ProcessorTransformInitData init_data;
1820
1821   init_data.cm_processor = cm_processor;
1822   init_data.byte_buffer = byte_buffer;
1823   init_data.float_buffer = float_buffer;
1824   init_data.width = width;
1825   init_data.height = height;
1826   init_data.channels = channels;
1827   init_data.predivide = predivide;
1828   init_data.float_from_byte = float_from_byte;
1829
1830   IMB_processor_apply_threaded(height,
1831                                sizeof(ProcessorTransformThread),
1832                                &init_data,
1833                                processor_transform_init_handle,
1834                                do_processor_transform_thread);
1835 }
1836
1837 /*********************** Color space transformation functions *************************/
1838
1839 /* Convert the whole buffer from specified by name color space to another -
1840  * internal implementation. */
1841 static void colormanagement_transform_ex(unsigned char *byte_buffer,
1842                                          float *float_buffer,
1843                                          int width,
1844                                          int height,
1845                                          int channels,
1846                                          const char *from_colorspace,
1847                                          const char *to_colorspace,
1848                                          bool predivide,
1849                                          bool do_threaded)
1850 {
1851   ColormanageProcessor *cm_processor;
1852
1853   if (from_colorspace[0] == '\0') {
1854     return;
1855   }
1856
1857   if (STREQ(from_colorspace, to_colorspace)) {
1858     /* if source and destination color spaces are identical, skip
1859      * threading overhead and simply do nothing
1860      */
1861     return;
1862   }
1863
1864   cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1865
1866   if (do_threaded) {
1867     processor_transform_apply_threaded(
1868         byte_buffer, float_buffer, width, height, channels, cm_processor, predivide, false);
1869   }
1870   else {
1871     if (byte_buffer != NULL) {
1872       IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
1873     }
1874     if (float_buffer != NULL) {
1875       IMB_colormanagement_processor_apply(
1876           cm_processor, float_buffer, width, height, channels, predivide);
1877     }
1878   }
1879
1880   IMB_colormanagement_processor_free(cm_processor);
1881 }
1882
1883 /* convert the whole buffer from specified by name color space to another */
1884 void IMB_colormanagement_transform(float *buffer,
1885                                    int width,
1886                                    int height,
1887                                    int channels,
1888                                    const char *from_colorspace,
1889                                    const char *to_colorspace,
1890                                    bool predivide)
1891 {
1892   colormanagement_transform_ex(
1893       NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
1894 }
1895
1896 /* convert the whole buffer from specified by name color space to another
1897  * will do threaded conversion
1898  */
1899 void IMB_colormanagement_transform_threaded(float *buffer,
1900                                             int width,
1901                                             int height,
1902                                             int channels,
1903                                             const char *from_colorspace,
1904                                             const char *to_colorspace,
1905                                             bool predivide)
1906 {
1907   colormanagement_transform_ex(
1908       NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
1909 }
1910
1911 /* Similar to functions above, but operates on byte buffer. */
1912 void IMB_colormanagement_transform_byte(unsigned char *buffer,
1913                                         int width,
1914                                         int height,
1915                                         int channels,
1916                                         const char *from_colorspace,
1917                                         const char *to_colorspace)
1918 {
1919   colormanagement_transform_ex(
1920       buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false);
1921 }
1922 void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
1923                                                  int width,
1924                                                  int height,
1925                                                  int channels,
1926                                                  const char *from_colorspace,
1927                                                  const char *to_colorspace)
1928 {
1929   colormanagement_transform_ex(
1930       buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
1931 }
1932
1933 /* Similar to above, but gets float buffer from display one. */
1934 void IMB_colormanagement_transform_from_byte(float *float_buffer,
1935                                              unsigned char *byte_buffer,
1936                                              int width,
1937                                              int height,
1938                                              int channels,
1939                                              const char *from_colorspace,
1940                                              const char *to_colorspace)
1941 {
1942   IMB_buffer_float_from_byte(float_buffer,
1943                              byte_buffer,
1944                              IB_PROFILE_SRGB,
1945                              IB_PROFILE_SRGB,
1946                              true,
1947                              width,
1948                              height,
1949                              width,
1950                              width);
1951   IMB_colormanagement_transform(
1952       float_buffer, width, height, channels, from_colorspace, to_colorspace, true);
1953 }
1954 void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer,
1955                                                       unsigned char *byte_buffer,
1956                                                       int width,
1957                                                       int height,
1958                                                       int channels,
1959                                                       const char *from_colorspace,
1960                                                       const char *to_colorspace)
1961 {
1962   ColormanageProcessor *cm_processor;
1963   if (from_colorspace == NULL || from_colorspace[0] == '\0') {
1964     return;
1965   }
1966   if (STREQ(from_colorspace, to_colorspace)) {
1967     /* Because this function always takes a byte buffer and returns a float buffer, it must
1968      * always do byte-to-float conversion of some kind. To avoid threading overhead
1969      * IMB_buffer_float_from_byte is used when color spaces are identical. See T51002.
1970      */
1971     IMB_buffer_float_from_byte(float_buffer,
1972                                byte_buffer,
1973                                IB_PROFILE_SRGB,
1974                                IB_PROFILE_SRGB,
1975                                false,
1976                                width,
1977                                height,
1978                                width,
1979                                width);
1980     IMB_premultiply_rect_float(float_buffer, 4, width, height);
1981     return;
1982   }
1983   cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1984   processor_transform_apply_threaded(
1985       byte_buffer, float_buffer, width, height, channels, cm_processor, false, true);
1986   IMB_colormanagement_processor_free(cm_processor);
1987 }
1988
1989 void IMB_colormanagement_transform_v4(float pixel[4],
1990                                       const char *from_colorspace,
1991                                       const char *to_colorspace)
1992 {
1993   ColormanageProcessor *cm_processor;
1994
1995   if (from_colorspace[0] == '\0') {
1996     return;
1997   }
1998
1999   if (STREQ(from_colorspace, to_colorspace)) {
2000     /* if source and destination color spaces are identical, skip
2001      * threading overhead and simply do nothing
2002      */
2003     return;
2004   }
2005
2006   cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2007
2008   IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2009
2010   IMB_colormanagement_processor_free(cm_processor);
2011 }
2012
2013 /* convert pixel from specified by descriptor color space to scene linear
2014  * used by performance-critical areas such as renderer and baker
2015  */
2016 void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
2017 {
2018   OCIO_ConstProcessorRcPtr *processor;
2019
2020   if (!colorspace) {
2021     /* should never happen */
2022     printf("%s: perform conversion from unknown color space\n", __func__);
2023     return;
2024   }
2025
2026   processor = colorspace_to_scene_linear_processor(colorspace);
2027
2028   if (processor) {
2029     OCIO_processorApplyRGB(processor, pixel);
2030   }
2031 }
2032
2033 /* same as above, but converts colors in opposite direction */
2034 void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
2035 {
2036   OCIO_ConstProcessorRcPtr *processor;
2037
2038   if (!colorspace) {
2039     /* should never happen */
2040     printf("%s: perform conversion from unknown color space\n", __func__);
2041     return;
2042   }
2043
2044   processor = colorspace_from_scene_linear_processor(colorspace);
2045
2046   if (processor) {
2047     OCIO_processorApplyRGB(processor, pixel);
2048   }
2049 }
2050
2051 void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4],
2052                                                        bool predivide,
2053                                                        ColorSpace *colorspace)
2054 {
2055   OCIO_ConstProcessorRcPtr *processor;
2056
2057   if (!colorspace) {
2058     /* should never happen */
2059     printf("%s: perform conversion from unknown color space\n", __func__);
2060     return;
2061   }
2062
2063   processor = colorspace_to_scene_linear_processor(colorspace);
2064
2065   if (processor) {
2066     if (predivide) {
2067       OCIO_processorApplyRGBA_predivide(processor, pixel);
2068     }
2069     else {
2070       OCIO_processorApplyRGBA(processor, pixel);
2071     }
2072   }
2073 }
2074
2075 void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
2076                                                     int width,
2077                                                     int height,
2078                                                     int channels,
2079                                                     struct ColorSpace *colorspace,
2080                                                     bool predivide)
2081 {
2082   OCIO_ConstProcessorRcPtr *processor;
2083
2084   if (!colorspace) {
2085     /* should never happen */
2086     printf("%s: perform conversion from unknown color space\n", __func__);
2087     return;
2088   }
2089
2090   processor = colorspace_to_scene_linear_processor(colorspace);
2091
2092   if (processor) {
2093     OCIO_PackedImageDesc *img;
2094
2095     img = OCIO_createOCIO_PackedImageDesc(buffer,
2096                                           width,
2097                                           height,
2098                                           channels,
2099                                           sizeof(float),
2100                                           (size_t)channels * sizeof(float),
2101                                           (size_t)channels * sizeof(float) * width);
2102
2103     if (predivide) {
2104       OCIO_processorApply_predivide(processor, img);
2105     }
2106     else {
2107       OCIO_processorApply(processor, img);
2108     }
2109
2110     OCIO_PackedImageDescRelease(img);
2111   }
2112 }
2113
2114 /* Conversion between color picking role. Typically we would expect such a
2115  * requirements:
2116  * - It is approximately perceptually linear, so that the HSV numbers and
2117  *   the HSV cube/circle have an intuitive distribution.
2118  * - It has the same gamut as the scene linear color space.
2119  * - Color picking values 0..1 map to scene linear values in the 0..1 range,
2120  *   so that picked albedo values are energy conserving.
2121  */
2122 void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
2123 {
2124   if (!global_color_picking_state.processor_to && !global_color_picking_state.failed) {
2125     /* Create processor if none exists. */
2126     BLI_mutex_lock(&processor_lock);
2127
2128     if (!global_color_picking_state.processor_to && !global_color_picking_state.failed) {
2129       global_color_picking_state.processor_to = create_colorspace_transform_processor(
2130           global_role_scene_linear, global_role_color_picking);
2131
2132       if (!global_color_picking_state.processor_to) {
2133         global_color_picking_state.failed = true;
2134       }
2135     }
2136
2137     BLI_mutex_unlock(&processor_lock);
2138   }
2139
2140   if (global_color_picking_state.processor_to) {
2141     OCIO_processorApplyRGB(global_color_picking_state.processor_to, pixel);
2142   }
2143 }
2144
2145 void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
2146 {
2147   if (!global_color_picking_state.processor_from && !global_color_picking_state.failed) {
2148     /* Create processor if none exists. */
2149     BLI_mutex_lock(&processor_lock);
2150
2151     if (!global_color_picking_state.processor_from && !global_color_picking_state.failed) {
2152       global_color_picking_state.processor_from = create_colorspace_transform_processor(
2153           global_role_color_picking, global_role_scene_linear);
2154
2155       if (!global_color_picking_state.processor_from) {
2156         global_color_picking_state.failed = true;
2157       }
2158     }
2159
2160     BLI_mutex_unlock(&processor_lock);
2161   }
2162
2163   if (global_color_picking_state.processor_from) {
2164     OCIO_processorApplyRGB(global_color_picking_state.processor_from, pixel);
2165   }
2166 }
2167
2168 /* Conversion between sRGB, for rare cases like hex color or copy/pasting
2169  * between UI theme and scene linear colors. */
2170 void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
2171 {
2172   mul_m3_v3(imbuf_rgb_to_xyz, pixel);
2173   mul_m3_v3(imbuf_xyz_to_linear_srgb, pixel);
2174   linearrgb_to_srgb_v3_v3(pixel, pixel);
2175 }
2176
2177 void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
2178 {
2179   srgb_to_linearrgb_v3_v3(pixel, pixel);
2180   mul_m3_v3(imbuf_linear_srgb_to_xyz, pixel);
2181   mul_m3_v3(imbuf_xyz_to_rgb, pixel);
2182 }
2183
2184 /* convert pixel from scene linear to display space using default view
2185  * used by performance-critical areas such as color-related widgets where we want to reduce
2186  * amount of per-widget allocations
2187  */
2188 void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
2189 {
2190   OCIO_ConstProcessorRcPtr *processor;
2191
2192   processor = display_from_scene_linear_processor(display);
2193
2194   if (processor) {
2195     OCIO_processorApplyRGB(processor, pixel);
2196   }
2197 }
2198
2199 /* same as above, but converts color in opposite direction */
2200 void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
2201 {
2202   OCIO_ConstProcessorRcPtr *processor;
2203
2204   processor = display_to_scene_linear_processor(display);
2205
2206   if (processor) {
2207     OCIO_processorApplyRGB(processor, pixel);
2208   }
2209 }
2210
2211 void IMB_colormanagement_pixel_to_display_space_v4(
2212     float result[4],
2213     const float pixel[4],
2214     const ColorManagedViewSettings *view_settings,
2215     const ColorManagedDisplaySettings *display_settings)
2216 {
2217   ColormanageProcessor *cm_processor;
2218
2219   copy_v4_v4(result, pixel);
2220
2221   cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2222   IMB_colormanagement_processor_apply_v4(cm_processor, result);
2223   IMB_colormanagement_processor_free(cm_processor);
2224 }
2225
2226 void IMB_colormanagement_pixel_to_display_space_v3(
2227     float result[3],
2228     const float pixel[3],
2229     const ColorManagedViewSettings *view_settings,
2230     const ColorManagedDisplaySettings *display_settings)
2231 {
2232   ColormanageProcessor *cm_processor;
2233
2234   copy_v3_v3(result, pixel);
2235
2236   cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2237   IMB_colormanagement_processor_apply_v3(cm_processor, result);
2238   IMB_colormanagement_processor_free(cm_processor);
2239 }
2240
2241 static void colormanagement_imbuf_make_display_space(
2242     ImBuf *ibuf,
2243     const ColorManagedViewSettings *view_settings,
2244     const ColorManagedDisplaySettings *display_settings,
2245     bool make_byte)
2246 {
2247   if (!ibuf->rect && make_byte) {
2248     imb_addrectImBuf(ibuf);
2249   }
2250
2251   colormanage_display_buffer_process_ex(
2252       ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect, view_settings, display_settings);
2253 }
2254
2255 void IMB_colormanagement_imbuf_make_display_space(
2256     ImBuf *ibuf,
2257     const ColorManagedViewSettings *view_settings,
2258     const ColorManagedDisplaySettings *display_settings)
2259 {
2260   colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
2261 }
2262
2263 /* prepare image buffer to be saved on disk, applying color management if needed
2264  * color management would be applied if image is saving as render result and if
2265  * file format is not expecting float buffer to be in linear space (currently
2266  * JPEG2000 and TIFF are such formats -- they're storing image as float but
2267  * file itself stores applied color space).
2268  *
2269  * Both byte and float buffers would contain applied color space, and result's
2270  * float_colorspace would be set to display color space. This should be checked
2271  * in image format write callback and if float_colorspace is not NULL, no color
2272  * space transformation should be applied on this buffer.
2273  */
2274 ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
2275                                            bool save_as_render,
2276                                            bool allocate_result,
2277                                            const ColorManagedViewSettings *view_settings,
2278                                            const ColorManagedDisplaySettings *display_settings,
2279                                            ImageFormatData *image_format_data)
2280 {
2281   ImBuf *colormanaged_ibuf = ibuf;
2282   bool do_colormanagement;
2283   bool is_movie = BKE_imtype_is_movie(image_format_data->imtype);
2284   bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
2285   bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
2286
2287   if (ibuf->rect_float && ibuf->rect &&
2288       (ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
2289     IMB_rect_from_float(ibuf);
2290     ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
2291   }
2292
2293   do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
2294
2295   if (do_colormanagement || do_alpha_under) {
2296     if (allocate_result) {
2297       colormanaged_ibuf = IMB_dupImBuf(ibuf);
2298     }
2299     else {
2300       /* Render pipeline is constructing image buffer itself,
2301        * but it's re-using byte and float buffers from render result make copy of this buffers
2302        * here sine this buffers would be transformed to other color space here.
2303        */
2304
2305       if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
2306         ibuf->rect = MEM_dupallocN(ibuf->rect);
2307         ibuf->mall |= IB_rect;
2308       }
2309
2310       if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
2311         ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
2312         ibuf->mall |= IB_rectfloat;
2313       }
2314     }
2315   }
2316
2317   /* If we're saving from RGBA to RGB buffer then it's not
2318    * so much useful to just ignore alpha -- it leads to bad
2319    * artifacts especially when saving byte images.
2320    *
2321    * What we do here is we're overlaying our image on top of
2322    * background color (which is currently black).
2323    *
2324    * This is quite much the same as what Gimp does and it
2325    * seems to be what artists expects from saving.
2326    *
2327    * Do a conversion here, so image format writers could
2328    * happily assume all the alpha tricks were made already.
2329    * helps keep things locally here, not spreading it to
2330    * all possible image writers we've got.
2331    */
2332   if (do_alpha_under) {
2333     float color[3] = {0, 0, 0};
2334
2335     if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
2336       IMB_alpha_under_color_float(
2337           colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
2338     }
2339
2340     if (colormanaged_ibuf->rect) {
2341       IMB_alpha_under_color_byte((unsigned char *)colormanaged_ibuf->rect,
2342                                  colormanaged_ibuf->x,
2343                                  colormanaged_ibuf->y,
2344                                  color);
2345     }
2346   }
2347
2348   if (do_colormanagement) {
2349     bool make_byte = false;
2350     const ImFileType *type;
2351
2352     /* for proper check whether byte buffer is required by a format or not
2353      * should be pretty safe since this image buffer is supposed to be used for
2354      * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
2355      */
2356     colormanaged_ibuf->ftype = BKE_image_imtype_to_ftype(image_format_data->imtype,
2357                                                          &colormanaged_ibuf->foptions);
2358
2359     /* if file format isn't able to handle float buffer itself,
2360      * we need to allocate byte buffer and store color managed
2361      * image there
2362      */
2363     for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
2364       if (type->save && type->ftype(type, colormanaged_ibuf)) {
2365         if ((type->flag & IM_FTYPE_FLOAT) == 0) {
2366           make_byte = true;
2367         }
2368
2369         break;
2370       }
2371     }
2372
2373     /* perform color space conversions */
2374     colormanagement_imbuf_make_display_space(
2375         colormanaged_ibuf, view_settings, display_settings, make_byte);
2376
2377     if (colormanaged_ibuf->rect_float) {
2378       /* float buffer isn't linear anymore,
2379        * image format write callback should check for this flag and assume
2380        * no space conversion should happen if ibuf->float_colorspace != NULL
2381        */
2382       colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings,
2383                                                                              display_settings);
2384     }
2385   }
2386
2387   if (colormanaged_ibuf != ibuf) {
2388     IMB_metadata_copy(colormanaged_ibuf, ibuf);
2389   }
2390
2391   return colormanaged_ibuf;
2392 }
2393
2394 void IMB_colormanagement_buffer_make_display_space(
2395     float *buffer,
2396     unsigned char *display_buffer,
2397     int width,
2398     int height,
2399     int channels,
2400     float dither,
2401     const ColorManagedViewSettings *view_settings,
2402     const ColorManagedDisplaySettings *display_settings)
2403 {
2404   ColormanageProcessor *cm_processor;
2405   size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
2406   float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
2407
2408   /* TODO(sergey): Convert float directly to byte buffer. */
2409
2410   memcpy(display_buffer_float, buffer, float_buffer_size);
2411
2412   cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2413
2414   processor_transform_apply_threaded(
2415       NULL, display_buffer_float, width, height, channels, cm_processor, true, false);
2416
2417   IMB_buffer_byte_from_float(display_buffer,
2418                              display_buffer_float,
2419                              channels,
2420                              dither,
2421                              IB_PROFILE_SRGB,
2422                              IB_PROFILE_SRGB,
2423                              true,
2424                              width,
2425                              height,
2426                              width,
2427                              width);
2428
2429   MEM_freeN(display_buffer_float);
2430   IMB_colormanagement_processor_free(cm_processor);
2431 }
2432
2433 /*********************** Public display buffers interfaces *************************/
2434
2435 /* acquire display buffer for given image buffer using specified view and display settings */
2436 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
2437                                           const ColorManagedViewSettings *view_settings,
2438                                           const ColorManagedDisplaySettings *display_settings,
2439                                           void **cache_handle)
2440 {
2441   unsigned char *display_buffer;
2442   size_t buffer_size;
2443   ColormanageCacheViewSettings cache_view_settings;
2444   ColormanageCacheDisplaySettings cache_display_settings;
2445   ColorManagedViewSettings default_view_settings;
2446   const ColorManagedViewSettings *applied_view_settings;
2447
2448   *cache_handle = NULL;
2449
2450   if (!ibuf->x || !ibuf->y) {
2451     return NULL;
2452   }
2453
2454   if (view_settings) {
2455     applied_view_settings = view_settings;
2456   }
2457   else {
2458     /* If no view settings were specified, use default ones, which will
2459      * attempt not to do any extra color correction. */
2460     IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
2461     applied_view_settings = &default_view_settings;
2462   }
2463
2464   /* early out: no float buffer and byte buffer is already in display space,
2465    * let's just use if
2466    */
2467   if (ibuf->rect_float == NULL && ibuf->rect_colorspace && ibuf->channels == 4) {
2468     if (is_ibuf_rect_in_display_space(ibuf, applied_view_settings, display_settings)) {
2469       return (unsigned char *)ibuf->rect;
2470     }
2471   }
2472
2473   colormanage_view_settings_to_cache(ibuf, &cache_view_settings, applied_view_settings);
2474   colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
2475
2476   if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) {
2477     if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
2478       IMB_partial_display_buffer_update_threaded(ibuf,
2479                                                  ibuf->rect_float,
2480                                                  (unsigned char *)ibuf->rect,
2481                                                  ibuf->x,
2482                                                  0,
2483                                                  0,
2484                                                  applied_view_settings,
2485                                                  display_settings,
2486                                                  ibuf->invalid_rect.xmin,
2487                                                  ibuf->invalid_rect.ymin,
2488                                                  ibuf->invalid_rect.xmax,
2489                                                  ibuf->invalid_rect.ymax,
2490                                                  false);
2491     }
2492
2493     BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0);
2494   }
2495
2496   BLI_thread_lock(LOCK_COLORMANAGE);
2497
2498   /* ensure color management bit fields exists */
2499   if (!ibuf->display_buffer_flags) {
2500     ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display,
2501                                              "imbuf display_buffer_flags");
2502   }
2503   else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
2504     /* all display buffers were marked as invalid from other areas,
2505      * now propagate this flag to internal color management routines
2506      */
2507     memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
2508
2509     ibuf->userflags &= ~IB_DISPLAY_BUFFER_INVALID;
2510   }
2511
2512   display_buffer = colormanage_cache_get(
2513       ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
2514
2515   if (display_buffer) {
2516     BLI_thread_unlock(LOCK_COLORMANAGE);
2517     return display_buffer;
2518   }
2519
2520   buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
2521   display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
2522
2523   colormanage_display_buffer_process(
2524       ibuf, display_buffer, applied_view_settings, display_settings);
2525
2526   colormanage_cache_put(
2527       ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
2528
2529   BLI_thread_unlock(LOCK_COLORMANAGE);
2530
2531   return display_buffer;
2532 }
2533
2534 /* same as IMB_display_buffer_acquire but gets view and display settings from context */
2535 unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
2536 {
2537   ColorManagedViewSettings *view_settings;
2538   ColorManagedDisplaySettings *display_settings;
2539
2540   IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
2541
2542   return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
2543 }
2544
2545 void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
2546                                         float *linear_buffer,
2547                                         int width,
2548                                         int height,
2549                                         int channels,
2550                                         const ColorManagedViewSettings *view_settings,
2551                                         const ColorManagedDisplaySettings *display_settings,
2552                                         bool predivide)
2553 {
2554   float *buffer;
2555   ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings,
2556                                                                                  display_settings);
2557
2558   buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float),
2559                        "display transform temp buffer");
2560   memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
2561
2562   IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
2563
2564   IMB_colormanagement_processor_free(cm_processor);
2565
2566   IMB_buffer_byte_from_float(display_buffer,
2567                              buffer,
2568                              channels,
2569                              0.0f,
2570                              IB_PROFILE_SRGB,
2571                              IB_PROFILE_SRGB,
2572                              false,
2573                              width,
2574                              height,
2575                              width,
2576                              width);
2577
2578   MEM_freeN(buffer);
2579 }
2580
2581 void IMB_display_buffer_release(void *cache_handle)
2582 {
2583   if (cache_handle) {
2584     BLI_thread_lock(LOCK_COLORMANAGE);
2585
2586     colormanage_cache_handle_release(cache_handle);
2587
2588     BLI_thread_unlock(LOCK_COLORMANAGE);
2589   }
2590 }
2591
2592 /*********************** Display functions *************************/
2593
2594 const char *colormanage_display_get_default_name(void)
2595 {
2596   OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2597   const char *display_name;
2598
2599   display_name = OCIO_configGetDefaultDisplay(config);
2600
2601   OCIO_configRelease(config);
2602
2603   return display_name;
2604 }
2605
2606 ColorManagedDisplay *colormanage_display_get_default(void)
2607 {
2608   const char *display_name = colormanage_display_get_default_name();
2609
2610   if (display_name[0] == '\0') {
2611     return NULL;
2612   }
2613
2614   return colormanage_display_get_named(display_name);
2615 }
2616
2617 ColorManagedDisplay *colormanage_display_add(const char *name)
2618 {
2619   ColorManagedDisplay *display;
2620   int index = 0;
2621
2622   if (global_displays.last) {
2623     ColorManagedDisplay *last_display = global_displays.last;
2624
2625     index = last_display->index;
2626   }
2627
2628   display = MEM_callocN(sizeof(ColorManagedDisplay), "ColorManagedDisplay");
2629
2630   display->index = index + 1;
2631
2632   BLI_strncpy(display->name, name, sizeof(display->name));
2633
2634   BLI_addtail(&global_displays, display);
2635
2636   return display;
2637 }
2638
2639 ColorManagedDisplay *colormanage_display_get_named(const char *name)
2640 {
2641   ColorManagedDisplay *display;
2642
2643   for (display = global_displays.first; display; display = display->next) {
2644     if (STREQ(display->name, name)) {
2645       return display;
2646     }
2647   }
2648
2649   return NULL;
2650 }
2651
2652 ColorManagedDisplay *colormanage_display_get_indexed(int index)
2653 {
2654   /* display indices are 1-based */
2655   return BLI_findlink(&global_displays, index - 1);
2656 }
2657
2658 int IMB_colormanagement_display_get_named_index(const char *name)
2659 {
2660   ColorManagedDisplay *display;
2661
2662   display = colormanage_display_get_named(name);
2663
2664   if (display) {
2665     return display->index;
2666   }
2667
2668   return 0;
2669 }
2670
2671 const char *IMB_colormanagement_display_get_indexed_name(int index)
2672 {
2673   ColorManagedDisplay *display;
2674
2675   display = colormanage_display_get_indexed(index);
2676
2677   if (display) {
2678     return display->name;
2679   }
2680
2681   return NULL;
2682 }
2683
2684 const char *IMB_colormanagement_display_get_default_name(void)
2685 {
2686   ColorManagedDisplay *display = colormanage_display_get_default();
2687
2688   return display->name;
2689 }
2690
2691 /* used by performance-critical pixel processing areas, such as color widgets */
2692 ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
2693 {
2694   return colormanage_display_get_named(name);
2695 }
2696
2697 const char *IMB_colormanagement_display_get_none_name(void)
2698 {
2699   if (colormanage_display_get_named("None") != NULL) {
2700     return "None";
2701   }
2702
2703   return colormanage_display_get_default_name();
2704 }
2705
2706 const char *IMB_colormanagement_display_get_default_view_transform_name(
2707     struct ColorManagedDisplay *display)
2708 {
2709   return colormanage_view_get_default_name(display);
2710 }
2711
2712 /*********************** View functions *************************/
2713
2714 const char *colormanage_view_get_default_name(const ColorManagedDisplay *display)
2715 {
2716   OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2717   const char *name;
2718
2719   name = OCIO_configGetDefaultView(config, display->name);
2720
2721   OCIO_configRelease(config);
2722
2723   return name;
2724 }
2725
2726 ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display)
2727 {
2728   const char *name = colormanage_view_get_default_name(display);
2729
2730   if (!name || name[0] == '\0') {
2731     return NULL;
2732   }
2733
2734   return colormanage_view_get_named(name);
2735 }
2736
2737 ColorManagedView *colormanage_view_add(const char *name)
2738 {
2739   ColorManagedView *view;
2740   int index = global_tot_view;
2741
2742   view = MEM_callocN(sizeof(ColorManagedView), "ColorManagedView");
2743   view->index = index + 1;
2744   BLI_strncpy(view->name, name, sizeof(view->name));
2745
2746   BLI_addtail(&global_views, view);
2747
2748   global_tot_view++;
2749
2750   return view;
2751 }
2752
2753 ColorManagedView *colormanage_view_get_named(const char *name)
2754 {
2755   ColorManagedView *view;
2756
2757   for (view = global_views.first; view; view = view->next) {
2758     if (STREQ(view->name, name)) {
2759       return view;
2760     }
2761   }
2762
2763   return NULL;
2764 }
2765
2766 ColorManagedView *colormanage_view_get_indexed(int index)
2767 {
2768   /* view transform indices are 1-based */
2769   return BLI_findlink(&global_views, index - 1);
2770 }
2771
2772 ColorManagedView *colormanage_view_get_named_for_display(const char *display_name,
2773                                                          const char *name)
2774 {
2775   ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2776   if (display == NULL) {
2777     return NULL;
2778   }
2779   LISTBASE_FOREACH (LinkData *, view_link, &display->views) {
2780     ColorManagedView *view = view_link->data;
2781     if (STRCASEEQ(name, view->name)) {
2782       return view;
2783     }
2784   }
2785   return NULL;
2786 }
2787
2788 int IMB_colormanagement_view_get_named_index(const char *name)
2789 {
2790   ColorManagedView *view = colormanage_view_get_named(name);
2791
2792   if (view) {
2793     return view->index;
2794   }
2795
2796   return 0;
2797 }
2798
2799 const char *IMB_colormanagement_view_get_indexed_name(int index)
2800 {
2801   ColorManagedView *view = colormanage_view_get_indexed(index);
2802
2803   if (view) {
2804     return view->name;
2805   }
2806
2807   return NULL;
2808 }
2809
2810 const char *IMB_colormanagement_view_get_default_name(const char *display_name)
2811 {
2812   ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2813   ColorManagedView *view = NULL;
2814
2815   if (display) {
2816     view = colormanage_view_get_default(display);
2817   }
2818
2819   if (view) {
2820     return view->name;
2821   }
2822
2823   return NULL;
2824 }
2825
2826 /*********************** Color space functions *************************/
2827
2828 static void colormanage_description_strip(char *description)
2829 {
2830   int i, n;
2831
2832   for (i = (int)strlen(description) - 1; i >= 0; i--) {
2833     if (ELEM(description[i], '\r', '\n')) {
2834       description[i] = '\0';
2835     }
2836     else {
2837       break;
2838     }
2839   }
2840
2841   for (i = 0, n = strlen(description); i < n; i++) {
2842     if (ELEM(description[i], '\r', '\n')) {
2843       description[i] = ' ';
2844     }
2845   }
2846 }
2847
2848 ColorSpace *colormanage_colorspace_add(const char *name,
2849                                        const char *description,
2850                                        bool is_invertible,
2851                                        bool is_data)
2852 {
2853   ColorSpace *colorspace, *prev_space;
2854   int counter = 1;
2855
2856   colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace");
2857
2858   BLI_strncpy(colorspace->name, name, sizeof(colorspace->name));
2859
2860   if (description) {
2861     BLI_strncpy(colorspace->description, description, sizeof(colorspace->description));
2862
2863     colormanage_description_strip(colorspace->description);
2864   }
2865
2866   colorspace->is_invertible = is_invertible;
2867   colorspace->is_data = is_data;
2868
2869   for (prev_space = global_colorspaces.first; prev_space; prev_space = prev_space->next) {
2870     if (BLI_strcasecmp(prev_space->name, colorspace->name) > 0) {
2871       break;
2872     }
2873
2874     prev_space->index = counter++;
2875   }
2876
2877   if (!prev_space) {
2878     BLI_addtail(&global_colorspaces, colorspace);
2879   }
2880   else {
2881     BLI_insertlinkbefore(&global_colorspaces, prev_space, colorspace);
2882   }
2883
2884   colorspace->index = counter++;
2885   for (; prev_space; prev_space = prev_space->next) {
2886     prev_space->index = counter++;
2887   }
2888
2889   global_tot_colorspace++;
2890
2891   return colorspace;
2892 }
2893
2894 ColorSpace *colormanage_colorspace_get_named(const char *name)
2895 {
2896   ColorSpace *colorspace;
2897
2898   for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
2899     if (STREQ(colorspace->name, name)) {
2900       return colorspace;
2901     }
2902   }
2903
2904   return NULL;
2905 }
2906
2907 ColorSpace *colormanage_colorspace_get_roled(int role)
2908 {
2909   const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
2910
2911   return colormanage_colorspace_get_named(role_colorspace);
2912 }
2913
2914 ColorSpace *colormanage_colorspace_get_indexed(int index)
2915 {
2916   /* color space indices are 1-based */
2917   return BLI_findlink(&global_colorspaces, index - 1);
2918 }
2919
2920 int IMB_colormanagement_colorspace_get_named_index(const char *name)
2921 {
2922   ColorSpace *colorspace;
2923
2924   colorspace = colormanage_colorspace_get_named(name);
2925
2926   if (colorspace) {
2927     return colorspace->index;
2928   }
2929
2930   return 0;
2931 }
2932
2933 const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
2934 {
2935   ColorSpace *colorspace;
2936
2937   colorspace = colormanage_colorspace_get_indexed(index);
2938
2939   if (colorspace) {
2940     return colorspace->name;
2941   }
2942
2943   return "";
2944 }
2945
2946 void IMB_colormanagement_colorspace_from_ibuf_ftype(
2947     ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
2948 {
2949   /* Don't modify non-color data space, it does not change with file type. */
2950   ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
2951
2952   if (colorspace && colorspace->is_data) {
2953     return;
2954   }
2955
2956   /* Get color space from file type. */
2957   const ImFileType *type;
2958
2959   for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
2960     if (type->save && type->ftype(type, ibuf)) {
2961       const char *role_colorspace;
2962
2963       role_colorspace = IMB_colormanagement_role_colorspace_name_get(type->default_save_role);
2964
2965       BLI_strncpy(colorspace_settings->name, role_colorspace, sizeof(colorspace_settings->name));
2966     }
2967   }
2968 }
2969
2970 /*********************** Looks functions *************************/
2971
2972 ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop)
2973 {
2974   ColorManagedLook *look;
2975   int index = global_tot_looks;
2976
2977   look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook");
2978   look->index = index + 1;
2979   BLI_strncpy(look->name, name, sizeof(look->name));
2980   BLI_strncpy(look->ui_name, name, sizeof(look->ui_name));
2981   BLI_strncpy(look->process_space, process_space, sizeof(look->process_space));
2982   look->is_noop = is_noop;
2983
2984   /* Detect view specific looks. */
2985   const char *separator_offset = strstr(look->name, " - ");
2986   if (separator_offset) {
2987     BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
2988     BLI_strncpy(look->ui_name, separator_offset + strlen(" - "), sizeof(look->ui_name));
2989   }
2990
2991   BLI_addtail(&global_looks, look);
2992
2993   global_tot_looks++;
2994
2995   return look;
2996 }
2997
2998 ColorManagedLook *colormanage_look_get_named(const char *name)
2999 {
3000   ColorManagedLook *look;
3001
3002   for (look = global_looks.first; look; look = look->next) {
3003     if (STREQ(look->name, name)) {
3004       return look;
3005     }
3006   }
3007
3008   return NULL;
3009 }
3010
3011 ColorManagedLook *colormanage_look_get_indexed(int index)
3012 {
3013   /* look indices are 1-based */
3014   return BLI_findlink(&global_looks, index - 1);
3015 }
3016
3017 int IMB_colormanagement_look_get_named_index(const char *name)
3018 {
3019   ColorManagedLook *look;
3020
3021   look = colormanage_look_get_named(name);
3022
3023   if (look) {
3024     return look->index;
3025   }
3026
3027   return 0;
3028 }
3029
3030 const char *IMB_colormanagement_look_get_indexed_name(int index)
3031 {
3032   ColorManagedLook *look;
3033
3034   look = colormanage_look_get_indexed(index);
3035
3036   if (look) {
3037     return look->name;
3038   }
3039
3040   return NULL;
3041 }
3042
3043 /*********************** RNA helper functions *************************/
3044
3045 void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
3046 {
3047   ColorManagedDisplay *display;
3048
3049   for (display = global_displays.first; display; display = display->next) {
3050     EnumPropertyItem item;
3051
3052     item.value = display->index;
3053     item.name = display->name;
3054     item.identifier = display->name;
3055     item.icon = 0;
3056     item.description = "";
3057
3058     RNA_enum_item_add(items, totitem, &item);
3059   }
3060 }
3061
3062 static void colormanagement_view_item_add(EnumPropertyItem **items,
3063                                           int *totitem,
3064                                           ColorManagedView *view)
3065 {
3066   EnumPropertyItem item;
3067
3068   item.value = view->index;
3069   item.name = view->name;
3070   item.identifier = view->name;
3071   item.icon = 0;
3072   item.description = "";
3073
3074   RNA_enum_item_add(items, totitem, &item);
3075 }
3076
3077 void IMB_colormanagement_view_items_add(EnumPropertyItem **items,
3078                                         int *totitem,
3079                                         const char *display_name)
3080 {
3081   ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3082   ColorManagedView *view;
3083
3084   if (display) {
3085     LinkData *display_view;
3086
3087     for (display_view = display->views.first; display_view; display_view = display_view->next) {
3088       view = display_view->data;
3089
3090       colormanagement_view_item_add(items, totitem, view);
3091     }
3092   }
3093 }
3094
3095 void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items,
3096                                         int *totitem,
3097                                         const char *view_name)
3098 {
3099   ColorManagedLook *look;
3100   const char *view_filter = NULL;
3101
3102   /* Test if this view transform is limited to specific looks. */
3103   for (look = global_looks.first; look; look = look->next) {
3104     if (STREQ(look->view, view_name)) {
3105       view_filter = view_name;
3106     }
3107   }
3108
3109   for (look = global_looks.first; look; look = look->next) {
3110     if (!look->is_noop && view_filter && !STREQ(look->view, view_filter)) {
3111       continue;
3112     }
3113
3114     EnumPropertyItem item;
3115
3116     item.value = look->index;
3117     item.name = look->ui_name;
3118     item.identifier = look->name;
3119     item.icon = 0;
3120     item.description = "";
3121
3122     RNA_enum_item_add(items, totitem, &item);
3123   }
3124 }
3125
3126 void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *totitem)
3127 {
3128   ColorSpace *colorspace;
3129
3130   for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
3131     EnumPropertyItem item;
3132
3133     if (!colorspace->is_invertible) {
3134       continue;
3135     }
3136
3137     item.value = colorspace->index;
3138     item.name = colorspace->name;
3139     item.identifier = colorspace->name;
3140     item.icon = 0;
3141     item.description = colorspace->description;
3142
3143     RNA_enum_item_add(items, totitem, &item);
3144   }
3145 }
3146
3147 /*********************** Partial display buffer update  *************************/
3148
3149 /*
3150  * Partial display update is supposed to be used by such areas as
3151  * compositor and renderer, This areas are calculating tiles of the
3152  * images and because of performance reasons only this tiles should
3153  * be color managed.
3154  * This gives nice visual feedback without slowing things down.
3155  *
3156  * Updating happens for active display transformation only, all
3157  * the rest buffers would be marked as dirty
3158  */
3159
3160 static void partial_buffer_update_rect(ImBuf *ibuf,
3161                                        unsigned char *display_buffer,
3162                                        const float *linear_buffer,
3163                                        const unsigned char *byte_buffer,
3164                                        int display_stride,
3165                                        int linear_stride,
3166                                        int linear_offset_x,
3167                                        int linear_offset_y,
3168                                        ColormanageProcessor *cm_processor,
3169                                        const int xmin,
3170                                        const int ymin,
3171                                        const int xmax,
3172                                        const int ymax)
3173 {
3174   int x, y;
3175   int channels = ibuf->channels;
3176   float dither = ibuf->dither;
3177   ColorSpace *rect_colorspace = ibuf->rect_colorspace;
3178   float *display_buffer_float = NULL;
3179   const int width = xmax - xmin;
3180   const int height = ymax - ymin;
3181   bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3182
3183   if (dither != 0.0f) {
3184     /* cm_processor is NULL in cases byte_buffer's space matches display
3185      * buffer's space
3186      * in this case we could skip extra transform and only apply dither
3187      * use 4 channels for easier byte->float->byte conversion here so
3188      * (this is only needed to apply dither, in other cases we'll convert
3189      * byte buffer to display directly)
3190      */
3191     if (!cm_processor) {
3192       channels = 4;
3193     }
3194
3195     display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float),
3196                                        "display buffer for dither");
3197   }
3198
3199   if (cm_processor) {
3200     for (y = ymin; y < ymax; y++) {
3201       for (x = xmin; x < xmax; x++) {
3202         size_t display_index = ((size_t)y * display_stride + x) * 4;
3203         size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride +
3204                                (x - linear_offset_x)) *
3205                               channels;
3206         float pixel[4];
3207
3208         if (linear_buffer) {
3209           if (channels == 4) {
3210             copy_v4_v4(pixel, (float *)linear_buffer + linear_index);
3211           }
3212           else if (channels == 3) {
3213             copy_v3_v3(pixel, (float *)linear_buffer + linear_index);
3214             pixel[3] = 1.0f;
3215           }
3216           else if (channels == 1) {
3217             pixel[0] = linear_buffer[linear_index];
3218           }
3219           else {
3220             BLI_assert(!"Unsupported number of channels in partial buffer update");
3221           }
3222         }
3223         else if (byte_buffer) {
3224           rgba_uchar_to_float(pixel, byte_buffer + linear_index);
3225           IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
3226           straight_to_premul_v4(pixel);
3227         }
3228
3229         if (!is_data) {
3230           IMB_colormanagement_processor_apply_pixel(cm_processor, pixel, channels);
3231         }
3232
3233         if (display_buffer_float) {
3234           size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
3235
3236           if (channels == 4) {
3237             copy_v4_v4(display_buffer_float + index, pixel);
3238           }
3239           else if (channels == 3) {
3240             copy_v3_v3(display_buffer_float + index, pixel);
3241           }
3242           else /* if (channels == 1) */ {
3243             display_buffer_float[index] = pixel[0];
3244           }
3245         }
3246         else {
3247           if (channels == 4) {
3248             float pixel_straight[4];
3249             premul_to_straight_v4_v4(pixel_straight, pixel);
3250             rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
3251           }
3252           else if (channels == 3) {
3253             rgb_float_to_uchar(display_buffer + display_index, pixel);
3254             display_buffer[display_index + 3] = 255;
3255           }
3256           else /* if (channels == 1) */ {
3257             display_buffer[display_index] = display_buffer[display_index + 1] =
3258                 display_buffer[display_index + 2] = display_buffer[display_index + 3] =
3259                     unit_float_to_uchar_clamp(pixel[0]);
3260           }
3261         }
3262       }
3263     }
3264   }
3265   else {
3266     if (display_buffer_float) {
3267       /* huh, for dither we need float buffer first, no cheaper way. currently */
3268       IMB_buffer_float_from_byte(display_buffer_float,
3269                                  byte_buffer,
3270                                  IB_PROFILE_SRGB,
3271                                  IB_PROFILE_SRGB,
3272                                  true,
3273                                  width,
3274                                  height,
3275                                  width,
3276                                  display_stride);
3277     }
3278     else {
3279       int i;
3280
3281       for (i = ymin; i < ymax; i++) {
3282         size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
3283         size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
3284
3285         memcpy(
3286             display_buffer + display_offset, byte_buffer + byte_offset, 4 * sizeof(char) * width);
3287       }
3288     }
3289   }
3290
3291   if (display_buffer_float) {
3292     size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
3293
3294     IMB_buffer_byte_from_float(display_buffer + display_index,
3295                                display_buffer_float,
3296                                channels,
3297                                dither,
3298                                IB_PROFILE_SRGB,
3299                                IB_PROFILE_SRGB,
3300                                true,
3301                                width,
3302                                height,
3303                                display_stride,
3304                                width);
3305
3306     MEM_freeN(display_buffer_float);
3307   }
3308 }
3309
3310 typedef struct PartialThreadData {
3311   ImBuf *ibuf;
3312   unsigned char *display_buffer;
3313   const float *linear_buffer;
3314   const unsigned char *byte_buffer;
3315   int display_stride;
3316   int linear_stride;
3317   int linear_offset_x, linear_offset_y;
3318   ColormanageProcessor *cm_processor;
3319   int xmin, ymin, xmax;
3320 } PartialThreadData;
3321
3322 static void partial_buffer_update_rect_thread_do(void *data_v,
3323                                                  int start_scanline,
3324                                                  int num_scanlines)
3325 {
3326   PartialThreadData *data = (PartialThreadData *)data_v;
3327   int ymin = data->ymin + start_scanline;
3328   partial_buffer_update_rect(data->ibuf,
3329                              data->display_buffer,
3330                              data->linear_buffer,
3331                              data->byte_buffer,
3332                              data->display_stride,
3333                              data->linear_stride,
3334                              data->linear_offset_x,
3335                              data->linear_offset_y,
3336                              data->cm_processor,
3337                              data->xmin,
3338                              ymin,
3339                              data->xmax,
3340                              ymin + num_scanlines);
3341 }
3342
3343 static void imb_partial_display_buffer_update_ex(
3344     ImBuf *ibuf,
3345     const float *linear_buffer,
3346     const unsigned char *byte_buffer,
3347     int stride,
3348     int offset_x,
3349     int offset_y,
3350     const ColorManagedViewSettings *view_settings,
3351     const ColorManagedDisplaySettings *display_settings,
3352     int xmin,
3353     int ymin,
3354     int xmax,
3355     int ymax,
3356     bool copy_display_to_byte_buffer,
3357     bool do_threads)
3358 {
3359   ColormanageCacheViewSettings cache_view_settings;
3360   ColormanageCacheDisplaySettings cache_display_settings;
3361   void *cache_handle = NULL;
3362   unsigned char *display_buffer = NULL;
3363   int buffer_width = ibuf->x;
3364
3365   if (ibuf->display_buffer_flags) {
3366     int view_flag, display_index;
3367
3368     colormanage_view_settings_to_cache(ibuf, &cache_view_settings, view_settings);
3369     colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
3370
3371     view_flag = 1 << (cache_view_settings.view - 1);
3372     display_index = cache_display_settings.display - 1;
3373
3374     BLI_thread_lock(LOCK_COLORMANAGE);
3375
3376     if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
3377       display_buffer = colormanage_cache_get(
3378           ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
3379     }
3380
3381     /* In some rare cases buffer's dimension could be changing directly from
3382      * different thread
3383      * this i.e. happens when image editor acquires render result
3384      */
3385     buffer_width = ibuf->x;
3386
3387     /* Mark all other buffers as invalid. */
3388     memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
3389     ibuf->display_buffer_flags[display_index] |= view_flag;
3390
3391     BLI_thread_unlock(LOCK_COLORMANAGE);
3392   }
3393
3394   if (display_buffer == NULL) {
3395     if (copy_display_to_byte_buffer) {
3396       display_buffer = (unsigned char *)ibuf->rect;
3397     }
3398   }
3399
3400   if (display_buffer) {
3401     ColormanageProcessor *cm_processor = NULL;
3402     bool skip_transform = false;
3403
3404     /* Byte buffer is assumed to be in imbuf's rect space, so if byte buffer
3405      * is known we could skip display->linear->display conversion in case
3406      * display color space matches imbuf's rect space.
3407      *
3408      * But if there's a float buffer it's likely operation was performed on
3409      * it first and byte buffer is likely to be out of date here.
3410      */
3411     if (linear_buffer == NULL && byte_buffer != NULL) {
3412       skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
3413     }
3414
3415     if (!skip_transform) {
3416       cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
3417     }
3418
3419     if (do_threads) {
3420       PartialThreadData data;
3421       data.ibuf = ibuf;
3422       data.display_buffer = display_buffer;
3423       data.linear_buffer = linear_buffer;
3424       data.byte_buffer = byte_buffer;
3425       data.display_stride = buffer_width;
3426       data.linear_stride = stride;
3427       data.linear_offset_x = offset_x;
3428       data.linear_offset_y = offset_y;
3429       data.cm_processor = cm_processor;
3430       data.xmin = xmin;
3431       data.ymin = ymin;
3432       data.xmax = xmax;
3433       IMB_processor_apply_threaded_scanlines(
3434           ymax - ymin, partial_buffer_update_rect_thread_do, &data);
3435     }
3436     else {
3437       partial_buffer_update_rect(ibuf,
3438                                  display_buffer,
3439                                  linear_buffer,
3440                                  byte_buffer,
3441                                  buffer_width,
3442                                  stride,
3443                                  offset_x,
3444                                  offset_y,
3445                                  cm_processor,
3446                                  xmin,
3447                                  ymin,
3448                                  xmax,
3449                                  ymax);
3450     }
3451
3452     if (cm_processor) {
3453       IMB_colormanagement_processor_free(cm_processor);
3454     }
3455
3456     IMB_display_buffer_release(cache_handle);
3457   }
3458
3459   if (copy_display_to_byte_buffer && (unsigned char *)ibuf->rect != display_buffer) {
3460     int y;
3461     for (y = ymin; y < ymax; y++) {
3462       size_t index = (size_t)y * buffer_width * 4;
3463       memcpy(
3464           (unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4);
3465     }
3466   }
3467 }
3468
3469 void IMB_partial_display_buffer_update(ImBuf *ibuf,
3470                                        const float *linear_buffer,
3471                                        const unsigned char *byte_buffer,
3472                                        int stride,
3473                                        int offset_x,
3474                                        int offset_y,
3475                                        const ColorManagedViewSettings *view_settings,
3476                                        const ColorManagedDisplaySettings *display_settings,
3477                                        int xmin,
3478                                        int ymin,
3479                                        int xmax,
3480                                        int ymax,
3481                                        bool copy_display_to_byte_buffer)
3482 {
3483   imb_partial_display_buffer_update_ex(ibuf,
3484                                        linear_buffer,
3485                                        byte_buffer,
3486                                        stride,
3487                                        offset_x,
3488                                        offset_y,
3489                                        view_settings,
3490                                        display_settings,
3491                                        xmin,
3492                                        ymin,
3493                                        xmax,
3494                                        ymax,
3495                                        copy_display_to_byte_buffer,
3496                                        false);
3497 }
3498
3499 void IMB_partial_display_buffer_update_threaded(
3500     struct ImBuf *ibuf,
3501     const float *linear_buffer,
3502     const unsigned char *byte_buffer,
3503     int stride,
3504     int offset_x,
3505     int offset_y,
3506     const struct ColorManagedViewSettings *view_settings,
3507     const struct ColorManagedDisplaySettings *display_settings,
3508     int xmin,
3509     int ymin,
3510     int xmax,
3511     int ymax,
3512     bool copy_display_to_byte_buffer)
3513 {
3514   int width = xmax - xmin;
3515   int height = ymax - ymin;
3516   bool do_threads = (((size_t)width) * height >= 64 * 64);
3517   imb_partial_display_buffer_update_ex(ibuf,
3518                                        linear_buffer,
3519                                        byte_buffer,
3520                                        stride,
3521                                        offset_x,
3522                                        offset_y,
3523                                        view_settings,
3524                                        display_settings,
3525                                        xmin,
3526                                        ymin,
3527                                        xmax,
3528                                        ymax,
3529                                        copy_display_to_byte_buffer,
3530                                        do_threads);
3531 }
3532
3533 void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
3534 {
3535   if (ibuf->invalid_rect.xmin == ibuf->invalid_rect.xmax) {
3536     BLI_rcti_init(&ibuf->invalid_rect, xmin, xmax, ymin, ymax);
3537   }
3538   else {
3539     rcti rect;
3540     BLI_rcti_init(&rect, xmin, xmax, ymin, ymax);
3541     BLI_rcti_union(&ibuf->invalid_rect, &rect);
3542   }
3543 }
3544
3545 /*********************** Pixel processor functions *************************/
3546
3547 ColormanageProcessor *IMB_colormanagement_display_processor_new(
3548     const ColorManagedViewSettings *view_settings,
3549     const ColorManagedDisplaySettings *display_settings)
3550 {
3551   ColormanageProcessor *cm_processor;
3552   ColorManagedViewSettings default_view_settings;
3553   const ColorManagedViewSettings *applied_view_settings;
3554   ColorSpace *display_space;
3555
3556   cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
3557
3558   if (view_settings) {
3559     applied_view_settings = view_settings;
3560   }
3561   else {
3562     IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
3563     applied_view_settings = &default_view_settings;
3564   }
3565
3566   display_space = display_transform_get_colorspace(applied_view_settings, display_settings);