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