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