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