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