code cleanup: spelling,
[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 #include "IMB_colormanagement.h"
32 #include "IMB_colormanagement_intern.h"
33
34 #include <string.h>
35 #include <math.h>
36
37 #include "DNA_color_types.h"
38 #include "DNA_image_types.h"
39 #include "DNA_movieclip_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_space_types.h"
43 #include "DNA_windowmanager_types.h"
44
45 #include "IMB_filter.h"
46 #include "IMB_imbuf.h"
47 #include "IMB_imbuf_types.h"
48 #include "IMB_filetype.h"
49 #include "IMB_moviecache.h"
50
51 #include "MEM_guardedalloc.h"
52
53 #include "BLI_blenlib.h"
54 #include "BLI_fileops.h"
55 #include "BLI_math.h"
56 #include "BLI_math_color.h"
57 #include "BLI_path_util.h"
58 #include "BLI_string.h"
59 #include "BLI_threads.h"
60
61 #include "BKE_colortools.h"
62 #include "BKE_context.h"
63 #include "BKE_image.h"
64 #include "BKE_utildefines.h"
65 #include "BKE_main.h"
66
67 #include "RNA_define.h"
68
69 #include <ocio_capi.h>
70
71 /*********************** Global declarations *************************/
72
73 #define MAX_COLORSPACE_NAME     64
74 #define DISPLAY_BUFFER_CHANNELS 4
75
76 /* ** list of all supported color spaces, displays and views */
77 static char global_role_scene_linear[MAX_COLORSPACE_NAME];
78 static char global_role_color_picking[MAX_COLORSPACE_NAME];
79 static char global_role_texture_painting[MAX_COLORSPACE_NAME];
80 static char global_role_default_byte[MAX_COLORSPACE_NAME];
81 static char global_role_default_float[MAX_COLORSPACE_NAME];
82 static char global_role_default_sequencer[MAX_COLORSPACE_NAME];
83
84 static ListBase global_colorspaces = {NULL};
85 static ListBase global_displays = {NULL};
86 static ListBase global_views = {NULL};
87
88 static int global_tot_colorspace = 0;
89 static int global_tot_display = 0;
90 static int global_tot_view = 0;
91
92 /* lock used by pre-cached processors getters, so processor wouldn't
93  * be created several times
94  * LOCK_COLORMANAGE can not be used since this mutex could be needed to
95  * be locked before pre-cached processor are creating
96  */
97 static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER;
98
99 typedef struct ColormanageProcessor {
100         OCIO_ConstProcessorRcPtr *processor;
101         CurveMapping *curve_mapping;
102         int is_data_result;
103 } ColormanageProcessor;
104
105 /*********************** Color managed cache *************************/
106
107 /* Cache Implementation Notes
108  * ==========================
109  *
110  * All color management cache stuff is stored in two properties of
111  * image buffers:
112  *
113  *   1. display_buffer_flags
114  *
115  *      This is a bit field which used to mark calculated transformations
116  *      for particular image buffer. Index inside of this array means index
117  *      of a color managed display. Element with given index matches view
118  *      transformations applied for a given display. So if bit B of array
119  *      element B is set to 1, this means display buffer with display index
120  *      of A and view transform of B was ever calculated for this imbuf.
121  *
122  *      In contrast with indices in global lists of displays and views this
123  *      indices are 0-based, not 1-based. This is needed to save some bytes
124  *      of memory.
125  *
126  *   2. colormanage_cache
127  *
128  *      This is a pointer to a structure which holds all data which is
129  *      needed for color management cache to work.
130  *
131  *      It contains two parts:
132  *        - data
133  *        - moviecache
134  *
135  *      Data field is used to store additional information about cached
136  *      buffers which affects on whether cached buffer could be used.
137  *      This data can't go to cache key because changes in this data
138  *      shouldn't lead extra buffers adding to cache, it shall
139  *      invalidate cached images.
140  *
141  *      Currently such a data contains only exposure and gamma, but
142  *      would likely extended further.
143  *
144  *      data field is not null only for elements of cache, not used for
145  *      original image buffers.
146  *
147  *      Color management cache is using generic MovieCache implementation
148  *      to make it easier to deal with memory limitation.
149  *
150  *      Currently color management is using the same memory limitation
151  *      pool as sequencer and clip editor are using which means color
152  *      managed buffers would be removed from the cache as soon as new
153  *      frames are loading for the movie clip and there's no space in
154  *      cache.
155  *
156  *      Every image buffer has got own movie cache instance, which
157  *      means keys for color managed buffers could be really simple
158  *      and look up in this cache would be fast and independent from
159  *      overall amount of color managed images.
160  */
161
162 /* NOTE: ColormanageCacheViewSettings and ColormanageCacheDisplaySettings are
163  *       quite the same as ColorManagedViewSettings and ColorManageDisplaySettings
164  *       but they holds indexes of all transformations and color spaces, not
165  *       their names.
166  *
167  *       This helps avoid extra colorspace / display / view lookup without
168  *       requiring to pass all variables which affects on display buffer
169  *       to color management cache system and keeps calls small and nice.
170  */
171 typedef struct ColormanageCacheViewSettings {
172         int flag;
173         int view;
174         float exposure;
175         float gamma;
176         CurveMapping *curve_mapping;
177 } ColormanageCacheViewSettings;
178
179 typedef struct ColormanageCacheDisplaySettings {
180         int display;
181 } ColormanageCacheDisplaySettings;
182
183 typedef struct ColormanageCacheKey {
184         int view;            /* view transformation used for display buffer */
185         int display;         /* display device name */
186 } ColormanageCacheKey;
187
188 typedef struct ColormnaageCacheData {
189         int flag;        /* view flags of cached buffer */
190         float exposure;  /* exposure value cached buffer is calculated with */
191         float gamma;     /* gamma value cached buffer is calculated with */
192         int predivide;   /* predivide flag of cached buffer */
193         CurveMapping *curve_mapping;  /* curve mapping used for cached buffer */
194         int curve_mapping_timestamp;  /* time stamp of curve mapping used for cached buffer */
195 } ColormnaageCacheData;
196
197 typedef struct ColormanageCache {
198         struct MovieCache *moviecache;
199
200         ColormnaageCacheData *data;
201 } ColormanageCache;
202
203 static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
204 {
205         if (!ibuf->colormanage_cache)
206                 return NULL;
207
208         return ibuf->colormanage_cache->moviecache;
209 }
210
211 static ColormnaageCacheData *colormanage_cachedata_get(const ImBuf *ibuf)
212 {
213         if (!ibuf->colormanage_cache)
214                 return NULL;
215
216         return ibuf->colormanage_cache->data;
217 }
218
219 static unsigned int colormanage_hashhash(const void *key_v)
220 {
221         ColormanageCacheKey *key = (ColormanageCacheKey *)key_v;
222
223         unsigned int rval = (key->display << 16) | (key->view % 0xffff);
224
225         return rval;
226 }
227
228 static int colormanage_hashcmp(const void *av, const void *bv)
229 {
230         const ColormanageCacheKey *a = (ColormanageCacheKey *) av;
231         const ColormanageCacheKey *b = (ColormanageCacheKey *) bv;
232
233         if (a->view < b->view)
234                 return -1;
235         else if (a->view > b->view)
236                 return 1;
237
238         if (a->display < b->display)
239                 return -1;
240         else if (a->display > b->display)
241                 return 1;
242
243         return 0;
244 }
245
246 static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
247 {
248         if (!ibuf->colormanage_cache)
249                 ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
250
251         if (!ibuf->colormanage_cache->moviecache) {
252                 struct MovieCache *moviecache;
253
254                 moviecache = IMB_moviecache_create("colormanage cache", sizeof(ColormanageCacheKey),
255                                                    colormanage_hashhash, colormanage_hashcmp);
256
257                 ibuf->colormanage_cache->moviecache = moviecache;
258         }
259
260         return ibuf->colormanage_cache->moviecache;
261 }
262
263 static void colormanage_cachedata_set(ImBuf *ibuf, ColormnaageCacheData *data)
264 {
265         if (!ibuf->colormanage_cache)
266                 ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
267
268         ibuf->colormanage_cache->data = data;
269 }
270
271 static void colormanage_view_settings_to_cache(ColormanageCacheViewSettings *cache_view_settings,
272                                                const ColorManagedViewSettings *view_settings)
273 {
274         int view = IMB_colormanagement_view_get_named_index(view_settings->view_transform);
275
276         cache_view_settings->view = view;
277         cache_view_settings->exposure = view_settings->exposure;
278         cache_view_settings->gamma = view_settings->gamma;
279         cache_view_settings->flag = view_settings->flag;
280         cache_view_settings->curve_mapping = view_settings->curve_mapping;
281 }
282
283 static void colormanage_display_settings_to_cache(ColormanageCacheDisplaySettings *cache_display_settings,
284                                                   const ColorManagedDisplaySettings *display_settings)
285 {
286         int display = IMB_colormanagement_display_get_named_index(display_settings->display_device);
287
288         cache_display_settings->display = display;
289 }
290
291 static void colormanage_settings_to_key(ColormanageCacheKey *key,
292                                         const ColormanageCacheViewSettings *view_settings,
293                                         const ColormanageCacheDisplaySettings *display_settings)
294 {
295         key->view = view_settings->view;
296         key->display = display_settings->display;
297 }
298
299 static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf, ColormanageCacheKey *key, void **cache_handle)
300 {
301         ImBuf *cache_ibuf;
302         struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
303
304         if (!moviecache) {
305                 /* if there's no moviecache it means no color management was applied on given image buffer before */
306
307                 return NULL;
308         }
309
310         *cache_handle = NULL;
311
312         cache_ibuf = IMB_moviecache_get(moviecache, key);
313
314         *cache_handle = cache_ibuf;
315
316         return cache_ibuf;
317 }
318
319 static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings,
320                                             const ColormanageCacheDisplaySettings *display_settings,
321                                             void **cache_handle)
322 {
323         ColormanageCacheKey key;
324         ImBuf *cache_ibuf;
325         int view_flag = 1 << (view_settings->view - 1);
326         int predivide = ibuf->flags & IB_cm_predivide;
327         CurveMapping *curve_mapping = view_settings->curve_mapping;
328         int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
329
330         colormanage_settings_to_key(&key, view_settings, display_settings);
331
332         /* check whether image was marked as dirty for requested transform */
333         if ((ibuf->display_buffer_flags[display_settings->display - 1] & view_flag) == 0) {
334                 return NULL;
335         }
336
337         cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
338
339         if (cache_ibuf) {
340                 ColormnaageCacheData *cache_data;
341
342                 BLI_assert(cache_ibuf->x == ibuf->x &&
343                            cache_ibuf->y == ibuf->y);
344
345                 /* only buffers with different color space conversions are being stored
346                  * in cache separately. buffer which were used only different exposure/gamma
347                  * are re-suing the same cached buffer
348                  *
349                  * check here which exposure/gamma/curve was used for cached buffer and if they're
350                  * different from requested buffer should be re-generated
351                  */
352                 cache_data = colormanage_cachedata_get(cache_ibuf);
353
354                 if (cache_data->exposure != view_settings->exposure ||
355                     cache_data->gamma != view_settings->gamma ||
356                         cache_data->predivide != predivide ||
357                         cache_data->flag != view_settings->flag ||
358                         cache_data->curve_mapping != curve_mapping ||
359                         cache_data->curve_mapping_timestamp != curve_mapping_timestamp)
360                 {
361                         *cache_handle = NULL;
362
363                         IMB_freeImBuf(cache_ibuf);
364
365                         return NULL;
366                 }
367
368                 return (unsigned char *) cache_ibuf->rect;
369         }
370
371         return NULL;
372 }
373
374 static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings,
375                                   const ColormanageCacheDisplaySettings *display_settings,
376                                   unsigned char *display_buffer, void **cache_handle)
377 {
378         ColormanageCacheKey key;
379         ImBuf *cache_ibuf;
380         ColormnaageCacheData *cache_data;
381         int view_flag = 1 << (view_settings->view - 1);
382         int predivide = ibuf->flags & IB_cm_predivide;
383         struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
384         CurveMapping *curve_mapping = view_settings->curve_mapping;
385         int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
386
387         colormanage_settings_to_key(&key, view_settings, display_settings);
388
389         /* mark display buffer as valid */
390         ibuf->display_buffer_flags[display_settings->display - 1] |= view_flag;
391
392         /* buffer itself */
393         cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
394         cache_ibuf->rect = (unsigned int *) display_buffer;
395
396         cache_ibuf->mall |= IB_rect;
397         cache_ibuf->flags |= IB_rect;
398
399         /* store data which is needed to check whether cached buffer could be used for color managed display settings */
400         cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data");
401         cache_data->exposure = view_settings->exposure;
402         cache_data->gamma = view_settings->gamma;
403         cache_data->predivide = predivide;
404         cache_data->flag = view_settings->flag;
405         cache_data->curve_mapping = curve_mapping;
406         cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
407
408         colormanage_cachedata_set(cache_ibuf, cache_data);
409
410         *cache_handle = cache_ibuf;
411
412         IMB_moviecache_put(moviecache, &key, cache_ibuf);
413 }
414
415 static void colormanage_cache_handle_release(void *cache_handle)
416 {
417         ImBuf *cache_ibuf = cache_handle;
418
419         IMB_freeImBuf(cache_ibuf);
420 }
421
422 /*********************** Initialization / De-initialization *************************/
423
424 static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role)
425 {
426         OCIO_ConstColorSpaceRcPtr *ociocs;
427
428         ociocs = OCIO_configGetColorSpace(config, role);
429
430         if (!ociocs && backup_role)
431                 ociocs = OCIO_configGetColorSpace(config, backup_role);
432
433         if (ociocs) {
434                 const char *name = OCIO_colorSpaceGetName(ociocs);
435
436                 /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
437                 BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
438                 OCIO_colorSpaceRelease(ociocs);
439         }
440         else {
441                 printf("Color management: Error could not find role %s role.\n", role);
442         }
443 }
444
445 static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
446 {
447         int tot_colorspace, tot_display, tot_display_view, index, viewindex, viewindex2;
448         const char *name;
449
450         /* get roles */
451         colormanage_role_color_space_name_get(config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL);
452         colormanage_role_color_space_name_get(config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING, NULL);
453         colormanage_role_color_space_name_get(config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT, NULL);
454         colormanage_role_color_space_name_get(config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER, OCIO_ROLE_SCENE_LINEAR);
455         colormanage_role_color_space_name_get(config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE, OCIO_ROLE_TEXTURE_PAINT);
456         colormanage_role_color_space_name_get(config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT, OCIO_ROLE_SCENE_LINEAR);
457
458         /* load colorspaces */
459         tot_colorspace = OCIO_configGetNumColorSpaces(config);
460         for (index = 0 ; index < tot_colorspace; index++) {
461                 OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
462                 const char *description;
463                 int is_invertible, is_data;
464
465                 name = OCIO_configGetColorSpaceNameByIndex(config, index);
466
467                 ocio_colorspace = OCIO_configGetColorSpace(config, name);
468                 description = OCIO_colorSpaceGetDescription(ocio_colorspace);
469                 is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
470                 is_data = OCIO_colorSpaceIsData(ocio_colorspace);
471
472                 colormanage_colorspace_add(name, description, is_invertible, is_data);
473
474                 OCIO_colorSpaceRelease(ocio_colorspace);
475         }
476
477         /* load displays */
478         viewindex2 = 0;
479         tot_display = OCIO_configGetNumDisplays(config);
480
481         for (index = 0 ; index < tot_display; index++) {
482                 const char *displayname;
483                 ColorManagedDisplay *display;
484
485                 displayname = OCIO_configGetDisplay(config, index);
486
487                 display = colormanage_display_add(displayname);
488
489                 /* load views */
490                 tot_display_view = OCIO_configGetNumViews(config, displayname);
491                 for (viewindex = 0 ; viewindex < tot_display_view; viewindex++, viewindex2++) {
492                         const char *viewname;
493                         ColorManagedView *view;
494                         LinkData *display_view;
495
496                         viewname = OCIO_configGetView(config, displayname, viewindex);
497
498                         /* first check if view transform with given name was already loaded */
499                         view = colormanage_view_get_named(viewname);
500
501                         if (!view) {
502                                 view = colormanage_view_add(viewname);
503                         }
504
505                         display_view = BLI_genericNodeN(view);
506
507                         BLI_addtail(&display->views, display_view);
508                 }
509         }
510
511         global_tot_display = tot_display;
512 }
513
514 static void colormanage_free_config(void)
515 {
516         ColorSpace *colorspace;
517         ColorManagedDisplay *display;
518
519         /* free color spaces */
520         colorspace = global_colorspaces.first;
521         while (colorspace) {
522                 ColorSpace *colorspace_next = colorspace->next;
523
524                 /* free precomputer processors */
525                 if (colorspace->to_scene_linear)
526                         OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) colorspace->to_scene_linear);
527
528                 if (colorspace->from_scene_linear)
529                         OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) colorspace->from_scene_linear);
530
531                 /* free color space itself */
532                 MEM_freeN(colorspace);
533
534                 colorspace = colorspace_next;
535         }
536
537         /* free displays */
538         display = global_displays.first;
539         while (display) {
540                 ColorManagedDisplay *display_next = display->next;
541
542                 /* free precomputer processors */
543                 if (display->to_scene_linear)
544                         OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) display->to_scene_linear);
545
546                 if (display->from_scene_linear)
547                         OCIO_processorRelease((OCIO_ConstProcessorRcPtr *) display->from_scene_linear);
548
549                 /* free list of views */
550                 BLI_freelistN(&display->views);
551
552                 MEM_freeN(display);
553                 display = display_next;
554         }
555
556         /* free views */
557         BLI_freelistN(&global_views);
558
559         OCIO_exit();
560 }
561
562 void colormanagement_init(void)
563 {
564         const char *ocio_env;
565         const char *configdir;
566         char configfile[FILE_MAX];
567         OCIO_ConstConfigRcPtr *config = NULL;
568
569         OCIO_init();
570
571         ocio_env = getenv("OCIO");
572
573         if (ocio_env && ocio_env[0] != '\0')
574                 config = OCIO_configCreateFromEnv();
575
576         if (config == NULL) {
577                 configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement");
578
579                 if (configdir) {
580                         BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
581
582 #ifdef WIN32
583                         {
584                                 /* quite a hack to support loading configuration from path with non-acii symbols */
585
586                                 char short_name[256];
587                                 BLI_get_short_name(short_name, configfile);
588                                 config = OCIO_configCreateFromFile(short_name);
589                         }
590 #else
591                         config = OCIO_configCreateFromFile(configfile);
592 #endif
593                 }
594         }
595
596         if (config == NULL) {
597                 printf("Color management: using fallback mode for management\n");
598
599                 config = OCIO_configCreateFallback();
600         }
601
602         if (config) {
603                 OCIO_setCurrentConfig(config);
604
605                 colormanage_load_config(config);
606
607                 OCIO_configRelease(config);
608         }
609
610         BLI_init_srgb_conversion();
611 }
612
613 void colormanagement_exit(void)
614 {
615         colormanage_free_config();
616 }
617
618 /*********************** Internal functions *************************/
619
620 void colormanage_cache_free(ImBuf *ibuf)
621 {
622         if (ibuf->display_buffer_flags) {
623                 MEM_freeN(ibuf->display_buffer_flags);
624
625                 ibuf->display_buffer_flags = NULL;
626         }
627
628         if (ibuf->colormanage_cache) {
629                 ColormnaageCacheData *cache_data = colormanage_cachedata_get(ibuf);
630                 struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
631
632                 if (cache_data) {
633                         MEM_freeN(cache_data);
634                 }
635
636                 if (moviecache) {
637                         IMB_moviecache_free(moviecache);
638                 }
639
640                 MEM_freeN(ibuf->colormanage_cache);
641
642                 ibuf->colormanage_cache = NULL;
643         }
644 }
645
646 static void display_transform_get_from_ctx(const bContext *C, ColorManagedViewSettings **view_settings_r,
647                                            ColorManagedDisplaySettings **display_settings_r)
648 {
649         Scene *scene = CTX_data_scene(C);
650         SpaceImage *sima = CTX_wm_space_image(C);
651
652         *view_settings_r = &scene->view_settings;
653         *display_settings_r = &scene->display_settings;
654
655         if (sima) {
656                 if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0)
657                         *view_settings_r = NULL;
658         }
659 }
660
661 static const char *display_transform_get_colorspace_name(const ColorManagedViewSettings *view_settings,
662                                                          const ColorManagedDisplaySettings *display_settings)
663 {
664         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
665
666         const char *display = display_settings->display_device;
667         const char *view = view_settings->view_transform;
668         const char *colorspace_name;
669
670         colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view);
671
672         OCIO_configRelease(config);
673
674         return colorspace_name;
675 }
676
677 static ColorSpace *display_transform_get_colorspace(const ColorManagedViewSettings *view_settings,
678                                                     const ColorManagedDisplaySettings *display_settings)
679 {
680         const char *colorspace_name = display_transform_get_colorspace_name(view_settings, display_settings);
681
682         if (colorspace_name)
683                 return colormanage_colorspace_get_named(colorspace_name);
684
685         return NULL;
686 }
687
688 static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display,
689                                                             float exposure, float gamma)
690 {
691         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
692         OCIO_DisplayTransformRcPtr *dt;
693         OCIO_ConstProcessorRcPtr *processor;
694
695         dt = OCIO_createDisplayTransform();
696
697         /* assuming handling buffer was already converted to scene linear space */
698         OCIO_displayTransformSetInputColorSpaceName(dt, global_role_scene_linear);
699         OCIO_displayTransformSetView(dt, view_transform);
700         OCIO_displayTransformSetDisplay(dt, display);
701
702         /* fstop exposure control */
703         if (exposure != 0.0f) {
704                 OCIO_MatrixTransformRcPtr *mt;
705                 float gain = powf(2.0f, exposure);
706                 const float scale4f[] = {gain, gain, gain, gain};
707                 float m44[16], offset4[4];
708
709                 OCIO_matrixTransformScale(m44, offset4, scale4f);
710                 mt = OCIO_createMatrixTransform();
711                 OCIO_matrixTransformSetValue(mt, m44, offset4);
712                 OCIO_displayTransformSetLinearCC(dt, (OCIO_ConstTransformRcPtr *) mt);
713
714                 OCIO_matrixTransformRelease(mt);
715         }
716
717         /* post-display gamma transform */
718         if (gamma != 1.0f) {
719                 OCIO_ExponentTransformRcPtr *et;
720                 float exponent = 1.0f / MAX2(FLT_EPSILON, gamma);
721                 const float exponent4f[] = {exponent, exponent, exponent, exponent};
722
723                 et = OCIO_createExponentTransform();
724                 OCIO_exponentTransformSetValue(et, exponent4f);
725                 OCIO_displayTransformSetDisplayCC(dt, (OCIO_ConstTransformRcPtr *) et);
726
727                 OCIO_exponentTransformRelease(et);
728         }
729
730         processor = OCIO_configGetProcessor(config, (OCIO_ConstTransformRcPtr *) dt);
731
732         OCIO_displayTransformRelease(dt);
733         OCIO_configRelease(config);
734
735         return processor;
736 }
737
738 static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
739                                                                   const char *to_colorspace)
740 {
741         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
742         OCIO_ConstProcessorRcPtr *processor;
743
744         processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
745
746         OCIO_configRelease(config);
747
748         return processor;
749 }
750
751 static OCIO_ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace)
752 {
753         if (colorspace->to_scene_linear == NULL) {
754                 BLI_mutex_lock(&processor_lock);
755
756                 if (colorspace->to_scene_linear == NULL) {
757                         OCIO_ConstProcessorRcPtr *to_scene_linear;
758                         to_scene_linear = create_colorspace_transform_processor(colorspace->name, global_role_scene_linear);
759                         colorspace->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *) to_scene_linear;
760                 }
761
762                 BLI_mutex_unlock(&processor_lock);
763         }
764
765         return (OCIO_ConstProcessorRcPtr *) colorspace->to_scene_linear;
766 }
767
768 static OCIO_ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace)
769 {
770         if (colorspace->from_scene_linear == NULL) {
771                 BLI_mutex_lock(&processor_lock);
772
773                 if (colorspace->from_scene_linear == NULL) {
774                         OCIO_ConstProcessorRcPtr *from_scene_linear;
775                         from_scene_linear = create_colorspace_transform_processor(global_role_scene_linear, colorspace->name);
776                         colorspace->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *) from_scene_linear;
777                 }
778
779                 BLI_mutex_unlock(&processor_lock);
780         }
781
782         return (OCIO_ConstProcessorRcPtr *) colorspace->from_scene_linear;
783 }
784
785 static OCIO_ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display)
786 {
787         if (display->from_scene_linear == NULL) {
788                 BLI_mutex_lock(&processor_lock);
789
790                 if (display->from_scene_linear == NULL) {
791                         const char *view_name = colormanage_view_get_default_name(display);
792                         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
793                         OCIO_ConstProcessorRcPtr *processor = NULL;
794
795                         if (view_name && config) {
796                                 const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name);
797                                 processor = OCIO_configGetProcessorWithNames(config, global_role_scene_linear, view_colorspace);
798
799                                 OCIO_configRelease(config);
800                         }
801
802                         display->from_scene_linear = (struct OCIO_ConstProcessorRcPtr *) processor;
803                 }
804
805                 BLI_mutex_unlock(&processor_lock);
806         }
807
808         return (OCIO_ConstProcessorRcPtr *) display->from_scene_linear;
809 }
810
811 static OCIO_ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display)
812 {
813         if (display->to_scene_linear == NULL) {
814                 BLI_mutex_lock(&processor_lock);
815
816                 if (display->to_scene_linear == NULL) {
817                         const char *view_name = colormanage_view_get_default_name(display);
818                         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
819                         OCIO_ConstProcessorRcPtr *processor = NULL;
820
821                         if (view_name && config) {
822                                 const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name);
823                                 processor = OCIO_configGetProcessorWithNames(config, view_colorspace, global_role_scene_linear);
824
825                                 OCIO_configRelease(config);
826                         }
827
828                         display->to_scene_linear = (struct OCIO_ConstProcessorRcPtr *) processor;
829                 }
830
831                 BLI_mutex_unlock(&processor_lock);
832         }
833
834         return (OCIO_ConstProcessorRcPtr *) display->to_scene_linear;
835 }
836
837 static void init_default_view_settings(const ColorManagedDisplaySettings *display_settings,
838                                        ColorManagedViewSettings *view_settings)
839 {
840         ColorManagedDisplay *display;
841         ColorManagedView *default_view = NULL;
842
843         display = colormanage_display_get_named(display_settings->display_device);
844
845         if (display)
846                 default_view = colormanage_view_get_default(display);
847
848         if (default_view)
849                 BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
850         else
851                 view_settings->view_transform[0] = '\0';
852
853         view_settings->flag = 0;
854         view_settings->gamma = 1.0f;
855         view_settings->exposure = 0.0f;
856         view_settings->curve_mapping = NULL;
857 }
858
859 static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
860 {
861         if (channels == 1) {
862                 pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
863         }
864         else if (channels == 2) {
865                 pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
866                 pixel[1] = curvemap_evaluateF(curve_mapping->cm, pixel[1]);
867         }
868         else {
869                 curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
870         }
871 }
872
873 void colorspace_set_default_role(char *colorspace, int size, int role)
874 {
875         if (colorspace && colorspace[0] == '\0') {
876                 const char *role_colorspace;
877
878                 role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
879
880                 BLI_strncpy(colorspace, role_colorspace, size);
881         }
882 }
883
884 void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
885 {
886         ibuf->rect_colorspace = colormanage_colorspace_get_named(global_role_default_byte);
887 }
888
889 void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
890 {
891         ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace);
892
893         if (colorspace && colorspace->is_data) {
894                 ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
895                 return;
896         }
897
898         if (ibuf->rect_float) {
899                 const char *to_colorspace = global_role_scene_linear;
900                 int predivide = ibuf->flags & IB_cm_predivide;
901
902                 if (ibuf->rect)
903                         imb_freerectImBuf(ibuf);
904
905                 IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
906                                               from_colorspace, to_colorspace, predivide);
907         }
908 }
909
910 /*********************** Generic functions *************************/
911
912 static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings, const char *what,
913                                                const ColorManagedDisplay *default_display)
914 {
915         if (display_settings->display_device[0] == '\0') {
916                 BLI_strncpy(display_settings->display_device, default_display->name, sizeof(display_settings->display_device));
917         }
918         else {
919                 ColorManagedDisplay *display = colormanage_display_get_named(display_settings->display_device);
920
921                 if (!display) {
922                         printf("Color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
923                                display_settings->display_device, what, default_display->name);
924
925                         BLI_strncpy(display_settings->display_device, default_display->name,
926                                     sizeof(display_settings->display_device));
927                 }
928         }
929 }
930
931 static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings,
932                                             ColorManagedViewSettings *view_settings, const char *what)
933 {
934         ColorManagedDisplay *display;
935         ColorManagedView *default_view = NULL;
936
937         if (view_settings->view_transform[0] == '\0') {
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         }
946         else {
947                 ColorManagedView *view = colormanage_view_get_named(view_settings->view_transform);
948
949                 if (!view) {
950                         display = colormanage_display_get_named(display_settings->display_device);
951
952                         if (display)
953                                 default_view = colormanage_view_get_default(display);
954
955                         if (default_view) {
956                                 printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
957                                        what, view_settings->view_transform, default_view->name);
958
959                                 BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
960                         }
961                 }
962         }
963
964         /* OCIO_TODO: move to do_versions() */
965         if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
966                 view_settings->exposure = 0.0f;
967                 view_settings->gamma = 1.0f;
968         }
969 }
970
971 static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
972 {
973         if (colorspace_settings->name[0] == '\0') {
974                 /* pass */
975         }
976         else {
977                 ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
978
979                 if (!colorspace) {
980                         printf("Color management: %s colorspace \"%s\" not found, will use default instead.\n",
981                                what, colorspace_settings->name);
982
983                         BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
984                 }
985         }
986
987         (void) what;
988 }
989
990 void IMB_colormanagement_check_file_config(Main *bmain)
991 {
992         Scene *scene;
993         Image *image;
994         MovieClip *clip;
995
996         ColorManagedDisplay *default_display;
997
998         default_display = colormanage_display_get_default();
999
1000         if (!default_display) {
1001                 /* happens when OCIO configuration is incorrect */
1002                 return;
1003         }
1004
1005         for (scene = bmain->scene.first; scene; scene = scene->id.next) {
1006                 ColorManagedColorspaceSettings *sequencer_colorspace_settings;
1007
1008                 colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
1009                 colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
1010
1011                 sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
1012
1013                 colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
1014
1015                 if (sequencer_colorspace_settings->name[0] == '\0') {
1016                         BLI_strncpy(sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
1017                 }
1018         }
1019
1020         /* ** check input color space settings ** */
1021
1022         for (image = bmain->image.first; image; image = image->id.next) {
1023                 colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
1024         }
1025
1026         for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
1027                 colormanage_check_colorspace_settings(&clip->colorspace_settings, "clip");
1028         }
1029 }
1030
1031 void IMB_colormanagement_validate_settings(ColorManagedDisplaySettings *display_settings,
1032                                            ColorManagedViewSettings *view_settings)
1033 {
1034         ColorManagedDisplay *display;
1035         ColorManagedView *default_view = NULL;
1036         LinkData *view_link;
1037
1038         display = colormanage_display_get_named(display_settings->display_device);
1039
1040         default_view = colormanage_view_get_default(display);
1041
1042         for (view_link = display->views.first; view_link; view_link = view_link->next) {
1043                 ColorManagedView *view = view_link->data;
1044
1045                 if (!strcmp(view->name, view_settings->view_transform))
1046                         break;
1047         }
1048
1049         if (view_link == NULL && default_view)
1050                 BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1051 }
1052
1053 const char *IMB_colormanagement_role_colorspace_name_get(int role)
1054 {
1055         switch (role) {
1056                 case COLOR_ROLE_SCENE_LINEAR:
1057                         return global_role_scene_linear;
1058                         break;
1059                 case COLOR_ROLE_COLOR_PICKING:
1060                         return global_role_color_picking;
1061                         break;
1062                 case COLOR_ROLE_TEXTURE_PAINTING:
1063                         return global_role_texture_painting;
1064                         break;
1065                 case COLOR_ROLE_DEFAULT_SEQUENCER:
1066                         return global_role_default_sequencer;
1067                         break;
1068                 case COLOR_ROLE_DEFAULT_FLOAT:
1069                         return global_role_default_float;
1070                         break;
1071                 case COLOR_ROLE_DEFAULT_BYTE:
1072                         return global_role_default_byte;
1073                         break;
1074                 default:
1075                         printf("Unknown role was passed to %s\n", __func__);
1076                         BLI_assert(0);
1077         }
1078
1079         return NULL;
1080 }
1081
1082 void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
1083 {
1084         ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1085
1086         if (colorspace && colorspace->is_data)
1087                 ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1088         else
1089                 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1090 }
1091
1092 void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
1093 {
1094         ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1095
1096         ibuf->float_colorspace = colorspace;
1097
1098         if (colorspace && colorspace->is_data)
1099                 ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1100         else
1101                 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1102 }
1103
1104 void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name)
1105 {
1106         ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1107
1108         ibuf->rect_colorspace = colorspace;
1109
1110         if (colorspace && colorspace->is_data)
1111                 ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA;
1112         else
1113                 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1114 }
1115
1116 /*********************** Threaded display buffer transform routines *************************/
1117
1118 typedef struct DisplayBufferThread {
1119         ColormanageProcessor *cm_processor;
1120
1121         float *buffer;
1122         unsigned char *byte_buffer;
1123
1124         float *display_buffer;
1125         unsigned char *display_buffer_byte;
1126
1127         int width;
1128         int start_line;
1129         int tot_line;
1130
1131         int channels;
1132         float dither;
1133         int predivide;
1134         int is_data;
1135
1136         const char *byte_colorspace;
1137         const char *float_colorspace;
1138 } DisplayBufferThread;
1139
1140 typedef struct DisplayBufferInitData {
1141         ImBuf *ibuf;
1142         ColormanageProcessor *cm_processor;
1143         float *buffer;
1144         unsigned char *byte_buffer;
1145
1146         float *display_buffer;
1147         unsigned char *display_buffer_byte;
1148
1149         int width;
1150
1151         const char *byte_colorspace;
1152         const char *float_colorspace;
1153 } DisplayBufferInitData;
1154
1155 static void display_buffer_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
1156 {
1157         DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
1158         DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v;
1159         ImBuf *ibuf = init_data->ibuf;
1160
1161         int predivide = ibuf->flags & IB_cm_predivide;
1162         int channels = ibuf->channels;
1163         float dither = ibuf->dither;
1164         int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
1165
1166         int offset = channels * start_line * ibuf->x;
1167         int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x;
1168
1169         memset(handle, 0, sizeof(DisplayBufferThread));
1170
1171         handle->cm_processor = init_data->cm_processor;
1172
1173         if (init_data->buffer)
1174                 handle->buffer = init_data->buffer + offset;
1175
1176         if (init_data->byte_buffer)
1177                 handle->byte_buffer = init_data->byte_buffer + offset;
1178
1179         if (init_data->display_buffer)
1180                 handle->display_buffer = init_data->display_buffer + offset;
1181
1182         if (init_data->display_buffer_byte)
1183                 handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
1184
1185         handle->width = ibuf->x;
1186
1187         handle->start_line = start_line;
1188         handle->tot_line = tot_line;
1189
1190         handle->channels = channels;
1191         handle->dither = dither;
1192         handle->predivide = predivide;
1193         handle->is_data = is_data;
1194
1195         handle->byte_colorspace = init_data->byte_colorspace;
1196         handle->float_colorspace = init_data->float_colorspace;
1197 }
1198
1199 static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
1200 {
1201         float *linear_buffer = NULL;
1202
1203         int channels = handle->channels;
1204         int width = handle->width;
1205         int height = handle->tot_line;
1206
1207         int buffer_size = channels * width * height;
1208
1209         int predivide = handle->predivide;
1210         int is_data = handle->is_data;
1211         int is_data_display = handle->cm_processor->is_data_result;
1212
1213         linear_buffer = MEM_callocN(buffer_size * sizeof(float), "color conversion linear buffer");
1214
1215         if (!handle->buffer) {
1216                 unsigned char *byte_buffer = handle->byte_buffer;
1217
1218                 const char *from_colorspace = handle->byte_colorspace;
1219                 const char *to_colorspace = global_role_scene_linear;
1220
1221                 float *fp;
1222                 unsigned char *cp;
1223                 int i;
1224
1225                 /* first convert byte buffer to float, keep in image space */
1226                 for (i = 0, fp = linear_buffer, cp = byte_buffer;
1227                      i < channels * width * height;
1228                      i++, fp++, cp++)
1229                 {
1230                         *fp = (float)(*cp) / 255.0f;
1231                 }
1232
1233                 if (!is_data && !is_data_display) {
1234                         /* convert float buffer to scene linear space */
1235                         IMB_colormanagement_transform(linear_buffer, width, height, channels,
1236                                                       from_colorspace, to_colorspace, predivide);
1237                 }
1238         }
1239         else if (handle->float_colorspace) {
1240                 /* currently float is non-linear only in sequencer, which is working
1241                  * in it's own color space even to handle float buffers.
1242                  * This color space is the same for byte and float images.
1243                  * Need to convert float buffer to linear space before applying display transform
1244                  */
1245
1246                 const char *from_colorspace = handle->float_colorspace;
1247                 const char *to_colorspace = global_role_scene_linear;
1248
1249                 memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1250
1251                 IMB_colormanagement_transform(linear_buffer, width, height, channels,
1252                                               from_colorspace, to_colorspace, predivide);
1253         }
1254         else {
1255                 /* some processors would want to modify float original buffer
1256                  * before converting it into display byte buffer, so we need to
1257                  * make sure original's ImBuf buffers wouldn't be modified by
1258                  * using duplicated buffer here
1259                  *
1260                  * NOTE: MEM_dupallocN can't be used because buffer could be
1261                  *       specified as an offset inside allocated buffer
1262                  */
1263
1264                 memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1265         }
1266
1267         return linear_buffer;
1268 }
1269
1270 static void *do_display_buffer_apply_thread(void *handle_v)
1271 {
1272         DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
1273         ColormanageProcessor *cm_processor = handle->cm_processor;
1274         float *display_buffer = handle->display_buffer;
1275         unsigned char *display_buffer_byte = handle->display_buffer_byte;
1276         int channels = handle->channels;
1277         int width = handle->width;
1278         int height = handle->tot_line;
1279         float dither = handle->dither;
1280         int predivide = handle->predivide;
1281         int is_data = handle->is_data;
1282
1283         if (cm_processor == NULL) {
1284                 if (display_buffer_byte) {
1285                         IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
1286                                                  FALSE, width, height, width, width);
1287                 }
1288
1289                 if (display_buffer) {
1290                         IMB_buffer_float_from_byte(display_buffer, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
1291                                                    FALSE, width, height, width, width);
1292                 }
1293         }
1294         else {
1295                 float *linear_buffer = display_buffer_apply_get_linear_buffer(handle);
1296
1297                 if (is_data) {
1298                         /* special case for data buffers - no color space conversions,
1299                          * only generate byte buffers
1300                          */
1301                 }
1302                 else {
1303                         /* apply processor */
1304                         IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, predivide);
1305                 }
1306
1307                 /* copy result to output buffers */
1308                 if (display_buffer_byte) {
1309                         /* do conversion */
1310                         IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer,
1311                                                    channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
1312                                                    predivide, width, height, width, width);
1313                 }
1314
1315                 if (display_buffer)
1316                         memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
1317
1318                 MEM_freeN(linear_buffer);
1319         }
1320
1321         return NULL;
1322 }
1323
1324 static void display_buffer_apply_threaded(ImBuf *ibuf, float *buffer, unsigned char *byte_buffer, float *display_buffer,
1325                                           unsigned char *display_buffer_byte, ColormanageProcessor *cm_processor)
1326 {
1327         DisplayBufferInitData init_data;
1328
1329         init_data.ibuf = ibuf;
1330         init_data.cm_processor = cm_processor;
1331         init_data.buffer = buffer;
1332         init_data.byte_buffer = byte_buffer;
1333         init_data.display_buffer = display_buffer;
1334         init_data.display_buffer_byte = display_buffer_byte;
1335
1336         if (ibuf->rect_colorspace != NULL) {
1337                 init_data.byte_colorspace = ibuf->rect_colorspace->name;
1338         }
1339         else {
1340                 /* happens for viewer images, which are not so simple to determine where to
1341                  * set image buffer's color spaces
1342                  */
1343                 init_data.byte_colorspace = global_role_default_byte;
1344         }
1345
1346         if (ibuf->float_colorspace != NULL) {
1347                 /* sequencer stores float buffers in non-linear space */
1348                 init_data.float_colorspace = ibuf->float_colorspace->name;
1349         }
1350         else {
1351                 init_data.float_colorspace = NULL;
1352         }
1353
1354         IMB_processor_apply_threaded(ibuf->y, sizeof(DisplayBufferThread), &init_data,
1355                                      display_buffer_init_handle, do_display_buffer_apply_thread);
1356 }
1357
1358 static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte,
1359                                                   const ColorManagedViewSettings *view_settings,
1360                                                   const ColorManagedDisplaySettings *display_settings)
1361 {
1362         ColormanageProcessor *cm_processor = NULL;
1363         int skip_transform = FALSE;
1364
1365         /* if we're going to transform byte buffer, check whether transformation would
1366          * happen to the same color space as byte buffer itself is
1367          * this would save byte -> float -> byte conversions making display buffer
1368          * computation noticeable faster
1369          */
1370         if (ibuf->rect_float == NULL && ibuf->rect_colorspace) {
1371                 if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) == 0 &&
1372                     view_settings->exposure == 0.0f &&
1373                     view_settings->gamma == 1.0f)
1374                 {
1375                         const char *from_colorspace = ibuf->rect_colorspace->name;
1376                         const char *to_colorspace = display_transform_get_colorspace_name(view_settings, display_settings);
1377
1378                         if (to_colorspace && !strcmp(from_colorspace, to_colorspace))
1379                                 skip_transform = TRUE;
1380                 }
1381         }
1382
1383         if (skip_transform == FALSE)
1384                 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1385
1386         display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect,
1387                                       display_buffer, display_buffer_byte, cm_processor);
1388
1389         if (cm_processor)
1390                 IMB_colormanagement_processor_free(cm_processor);
1391 }
1392
1393 static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer,
1394                                                const ColorManagedViewSettings *view_settings,
1395                                                const ColorManagedDisplaySettings *display_settings)
1396 {
1397         colormanage_display_buffer_process_ex(ibuf, NULL, display_buffer, view_settings, display_settings);
1398 }
1399
1400 /*********************** Threaded processor transform routines *************************/
1401
1402 typedef struct ProcessorTransformThread {
1403         ColormanageProcessor *cm_processor;
1404         float *buffer;
1405         int width;
1406         int start_line;
1407         int tot_line;
1408         int channels;
1409         int predivide;
1410 } ProcessorTransformThread;
1411
1412 typedef struct ProcessorTransformInit {
1413         ColormanageProcessor *cm_processor;
1414         float *buffer;
1415         int width;
1416         int height;
1417         int channels;
1418         int predivide;
1419 } ProcessorTransformInitData;
1420
1421 static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
1422 {
1423         ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
1424         ProcessorTransformInitData *init_data = (ProcessorTransformInitData *) init_data_v;
1425
1426         int channels = init_data->channels;
1427         int width = init_data->width;
1428         int predivide = init_data->predivide;
1429
1430         int offset = channels * start_line * width;
1431
1432         memset(handle, 0, sizeof(ProcessorTransformThread));
1433
1434         handle->cm_processor = init_data->cm_processor;
1435
1436         handle->buffer = init_data->buffer + offset;
1437
1438         handle->width = width;
1439
1440         handle->start_line = start_line;
1441         handle->tot_line = tot_line;
1442
1443         handle->channels = channels;
1444         handle->predivide = predivide;
1445 }
1446
1447 static void *do_processor_transform_thread(void *handle_v)
1448 {
1449         ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
1450         float *buffer = handle->buffer;
1451         int channels = handle->channels;
1452         int width = handle->width;
1453         int height = handle->tot_line;
1454         int predivide = handle->predivide;
1455
1456         IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide);
1457
1458         return NULL;
1459 }
1460
1461 static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels,
1462                                                ColormanageProcessor *cm_processor, int predivide)
1463 {
1464         ProcessorTransformInitData init_data;
1465
1466         init_data.cm_processor = cm_processor;
1467         init_data.buffer = buffer;
1468         init_data.width = width;
1469         init_data.height = height;
1470         init_data.channels = channels;
1471         init_data.predivide = predivide;
1472
1473         IMB_processor_apply_threaded(height, sizeof(ProcessorTransformThread), &init_data,
1474                                      processor_transform_init_handle, do_processor_transform_thread);
1475 }
1476
1477 /*********************** Color space transformation functions *************************/
1478
1479 /* convert the whole buffer from specified by name color space to another - internal implementation */
1480 static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace,
1481                                          const char *to_colorspace, int predivide, int do_threaded)
1482 {
1483         ColormanageProcessor *cm_processor;
1484
1485         if (from_colorspace[0] == '\0') {
1486                 return;
1487         }
1488
1489         if (!strcmp(from_colorspace, to_colorspace)) {
1490                 /* if source and destination color spaces are identical, skip
1491                  * threading overhead and simply do nothing
1492                  */
1493                 return;
1494         }
1495
1496         cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1497
1498         if (do_threaded)
1499                 processor_transform_apply_threaded(buffer, width, height, channels, cm_processor, predivide);
1500         else
1501                 IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
1502
1503         IMB_colormanagement_processor_free(cm_processor);
1504 }
1505
1506 /* convert the whole buffer from specified by name color space to another */
1507 void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
1508                                    const char *from_colorspace, const char *to_colorspace, int predivide)
1509 {
1510         colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, FALSE);
1511 }
1512
1513 /* convert the whole buffer from specified by name color space to another
1514  * will do threaded conversion
1515  */
1516 void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
1517                                             const char *from_colorspace, const char *to_colorspace, int predivide)
1518 {
1519         colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, TRUE);
1520 }
1521
1522 void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
1523 {
1524         ColormanageProcessor *cm_processor;
1525
1526         if (from_colorspace[0] == '\0') {
1527                 return;
1528         }
1529
1530         if (!strcmp(from_colorspace, to_colorspace)) {
1531                 /* if source and destination color spaces are identical, skip
1532                  * threading overhead and simply do nothing
1533                  */
1534                 return;
1535         }
1536
1537         cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1538
1539         IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
1540
1541         IMB_colormanagement_processor_free(cm_processor);
1542 }
1543
1544 /* convert pixel from specified by descriptor color space to scene linear
1545  * used by performance-critical areas such as renderer and baker
1546  */
1547 void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
1548 {
1549         OCIO_ConstProcessorRcPtr *processor;
1550
1551         if (!colorspace) {
1552                 /* should never happen */
1553                 printf("%s: perform conversion from unknown color space\n", __func__);
1554                 return;
1555         }
1556
1557         processor = colorspace_to_scene_linear_processor(colorspace);
1558
1559         if (processor)
1560                 OCIO_processorApplyRGB(processor, pixel);
1561 }
1562
1563 /* same as above, but converts colors in opposite direction */
1564 void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
1565 {
1566         OCIO_ConstProcessorRcPtr *processor;
1567
1568         if (!colorspace) {
1569                 /* should never happen */
1570                 printf("%s: perform conversion from unknown color space\n", __func__);
1571                 return;
1572         }
1573
1574         processor = colorspace_from_scene_linear_processor(colorspace);
1575
1576         if (processor)
1577                 OCIO_processorApplyRGB(processor, pixel);
1578 }
1579
1580 void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide)
1581 {
1582         OCIO_ConstProcessorRcPtr *processor;
1583
1584         if (!colorspace) {
1585                 /* should never happen */
1586                 printf("%s: perform conversion from unknown color space\n", __func__);
1587                 return;
1588         }
1589
1590         processor = colorspace_to_scene_linear_processor(colorspace);
1591
1592         if (processor) {
1593                 OCIO_PackedImageDesc *img;
1594
1595                 img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
1596                                                  channels * sizeof(float), channels * sizeof(float) * width);
1597
1598                 if (predivide)
1599                         OCIO_processorApply_predivide(processor, img);
1600                 else
1601                         OCIO_processorApply(processor, img);
1602
1603                 OCIO_OCIO_PackedImageDescRelease(img);
1604         }
1605 }
1606
1607 /* convert pixel from scene linear to display space using default view
1608  * used by performance-critical areas such as color-related widgets where we want to reduce
1609  * amount of per-widget allocations
1610  */
1611 void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
1612 {
1613         OCIO_ConstProcessorRcPtr *processor;
1614
1615         processor = display_from_scene_linear_processor(display);
1616
1617         if (processor)
1618                 OCIO_processorApplyRGB(processor, pixel);
1619 }
1620
1621 /* same as above, but converts color in opposite direction */
1622 void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
1623 {
1624         OCIO_ConstProcessorRcPtr *processor;
1625
1626         processor = display_to_scene_linear_processor(display);
1627
1628         if (processor)
1629                 OCIO_processorApplyRGB(processor, pixel);
1630 }
1631
1632 void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4],
1633                                                    const ColorManagedViewSettings *view_settings,
1634                                                    const ColorManagedDisplaySettings *display_settings)
1635 {
1636         ColormanageProcessor *cm_processor;
1637
1638         copy_v4_v4(result, pixel);
1639
1640         cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1641         IMB_colormanagement_processor_apply_v4(cm_processor, result);
1642         IMB_colormanagement_processor_free(cm_processor);
1643 }
1644
1645 void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float pixel[3],
1646                                                    const ColorManagedViewSettings *view_settings,
1647                                                    const ColorManagedDisplaySettings *display_settings)
1648 {
1649         ColormanageProcessor *cm_processor;
1650
1651         copy_v3_v3(result, pixel);
1652
1653         cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1654         IMB_colormanagement_processor_apply_v3(cm_processor, result);
1655         IMB_colormanagement_processor_free(cm_processor);
1656 }
1657
1658 static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
1659                                                      const ColorManagedDisplaySettings *display_settings, int make_byte)
1660 {
1661         if (!ibuf->rect && make_byte)
1662                 imb_addrectImBuf(ibuf);
1663
1664         if (global_tot_display == 0 || global_tot_view == 0) {
1665                 IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
1666                                             ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
1667         }
1668         else {
1669                 colormanage_display_buffer_process_ex(ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect,
1670                                                       view_settings, display_settings);
1671         }
1672 }
1673
1674 void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
1675                                                   const ColorManagedDisplaySettings *display_settings)
1676 {
1677         colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, FALSE);
1678 }
1679
1680 /* prepare image buffer to be saved on disk, applying color management if needed
1681  * color management would be applied if image is saving as render result and if
1682  * file format is not expecting float buffer to be in linear space (currently
1683  * JPEG2000 and TIFF are such formats -- they're storing image as float but
1684  * file itself stores applied color space).
1685  *
1686  * Both byte and float buffers would contain applied color space, and result's
1687  * float_colorspace would be set to display color space. This should be checked
1688  * in image format write callback and if float_colorspace is not NULL, no color
1689  * space transformation should be applied on this buffer.
1690  */
1691 ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int allocate_result, const ColorManagedViewSettings *view_settings,
1692                                            const ColorManagedDisplaySettings *display_settings, ImageFormatData *image_format_data)
1693 {
1694         ImBuf *colormanaged_ibuf = ibuf;
1695         int do_colormanagement;
1696         int is_movie = BKE_imtype_is_movie(image_format_data->imtype);
1697         int requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
1698
1699         do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
1700
1701         if (do_colormanagement) {
1702                 int make_byte = FALSE;
1703                 ImFileType *type;
1704
1705                 if (allocate_result) {
1706                         colormanaged_ibuf = IMB_dupImBuf(ibuf);
1707                 }
1708                 else {
1709                         /* render pipeline is constructing image buffer itself, but it's re-using byte and float buffers from render result
1710                          * make copy of this buffers here sine this buffers would be transformed to other color space here
1711                          */
1712
1713                         if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
1714                                 ibuf->rect = MEM_dupallocN(ibuf->rect);
1715                                 ibuf->mall |= IB_rect;
1716                         }
1717
1718                         if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
1719                                 ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
1720                                 ibuf->mall |= IB_rectfloat;
1721                         }
1722                 }
1723
1724                 /* for proper check whether byte buffer is required by a format or not
1725                  * should be pretty safe since this image buffer is supposed to be used for
1726                  * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
1727                  */
1728                 colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format_data->imtype);
1729
1730                 /* if file format isn't able to handle float buffer itself,
1731                  * we need to allocate byte buffer and store color managed
1732                  * image there
1733                  */
1734                 for (type = IMB_FILE_TYPES; type->is_a; type++) {
1735                         if (type->save && type->ftype(type, colormanaged_ibuf)) {
1736                                 if ((type->flag & IM_FTYPE_FLOAT) == 0)
1737                                         make_byte = TRUE;
1738
1739                                 break;
1740                         }
1741                 }
1742
1743                 /* perform color space conversions */
1744                 colormanagement_imbuf_make_display_space(colormanaged_ibuf, view_settings, display_settings, make_byte);
1745
1746                 if (colormanaged_ibuf->rect_float) {
1747                         /* float buffer isn't linear anymore,
1748                          * image format write callback should check for this flag and assume
1749                          * no space conversion should happen if ibuf->float_colorspace != NULL
1750                          */
1751                         colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings, display_settings);
1752                 }
1753         }
1754
1755         return colormanaged_ibuf;
1756 }
1757
1758 static void imbuf_verify_float(ImBuf *ibuf)
1759 {
1760         /* multiple threads could request for display buffer at once and in case
1761          * view transform is not used it'll lead to display buffer calculated
1762          * several times
1763          * it is harmless, but would take much more time (assuming thread lock
1764          * happens faster than running float->byte conversion for average image)
1765          */
1766         BLI_lock_thread(LOCK_COLORMANAGE);
1767
1768         if (ibuf->rect_float && (ibuf->rect == NULL || (ibuf->userflags & IB_RECT_INVALID))) {
1769                 IMB_rect_from_float(ibuf);
1770
1771                 ibuf->userflags &= ~IB_RECT_INVALID;
1772         }
1773
1774         BLI_unlock_thread(LOCK_COLORMANAGE);
1775 }
1776
1777 /*********************** Public display buffers interfaces *************************/
1778
1779 /* acquire display buffer for given image buffer using specified view and display settings */
1780 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
1781                                           const ColorManagedDisplaySettings *display_settings, void **cache_handle)
1782 {
1783         *cache_handle = NULL;
1784
1785         if (!ibuf->x || !ibuf->y)
1786                 return NULL;
1787
1788         if (global_tot_display == 0 || global_tot_view == 0) {
1789                 /* if there's no view transform or display transforms, fallback to standard sRGB/linear conversion
1790                  * the same logic would be used if OCIO is disabled
1791                  */
1792
1793                 imbuf_verify_float(ibuf);
1794
1795                 return (unsigned char *) ibuf->rect;
1796         }
1797         else {
1798                 unsigned char *display_buffer;
1799                 int buffer_size;
1800                 ColormanageCacheViewSettings cache_view_settings;
1801                 ColormanageCacheDisplaySettings cache_display_settings;
1802                 ColorManagedViewSettings default_view_settings;
1803                 const ColorManagedViewSettings *applied_view_settings;
1804
1805                 if (view_settings) {
1806                         applied_view_settings = view_settings;
1807                 }
1808                 else {
1809                         /* if no view settings were specified, use default display transformation
1810                          * this happens for images which don't want to be displayed with render settings
1811                          */
1812
1813                         init_default_view_settings(display_settings,  &default_view_settings);
1814                         applied_view_settings = &default_view_settings;
1815                 }
1816
1817                 colormanage_view_settings_to_cache(&cache_view_settings, applied_view_settings);
1818                 colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
1819
1820                 BLI_lock_thread(LOCK_COLORMANAGE);
1821
1822                 /* ensure color management bit fields exists */
1823                 if (!ibuf->display_buffer_flags) {
1824                         if (global_tot_display)
1825                                 ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display, "imbuf display_buffer_flags");
1826                 }
1827                 else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
1828                         /* all display buffers were marked as invalid from other areas,
1829                          * now propagate this flag to internal color management routines
1830                          */
1831                         memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
1832
1833                         ibuf->userflags &= ~IB_DISPLAY_BUFFER_INVALID;
1834                 }
1835
1836                 display_buffer = colormanage_cache_get(ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
1837
1838                 if (display_buffer) {
1839                         BLI_unlock_thread(LOCK_COLORMANAGE);
1840                         return display_buffer;
1841                 }
1842
1843                 buffer_size = DISPLAY_BUFFER_CHANNELS * ibuf->x * ibuf->y * sizeof(char);
1844                 display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
1845
1846                 colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
1847
1848                 colormanage_cache_put(ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
1849
1850                 BLI_unlock_thread(LOCK_COLORMANAGE);
1851
1852                 return display_buffer;
1853         }
1854 }
1855
1856 /* same as IMB_display_buffer_acquire but gets view and display settings from context */
1857 unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
1858 {
1859         ColorManagedViewSettings *view_settings;
1860         ColorManagedDisplaySettings *display_settings;
1861
1862         display_transform_get_from_ctx(C, &view_settings, &display_settings);
1863
1864         return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
1865 }
1866
1867 void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height,
1868                                         int channels, const ColorManagedViewSettings *view_settings,
1869                                         const ColorManagedDisplaySettings *display_settings, int predivide)
1870 {
1871         if (global_tot_display == 0 || global_tot_view == 0) {
1872                 IMB_buffer_byte_from_float(display_buffer, linear_buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, FALSE,
1873                                            width, height, width, width);
1874         }
1875         else {
1876                 float *buffer;
1877                 ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1878
1879                 buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer");
1880                 memcpy(buffer, linear_buffer, channels * width * height * sizeof(float));
1881
1882                 IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
1883
1884                 IMB_colormanagement_processor_free(cm_processor);
1885
1886                 IMB_buffer_byte_from_float(display_buffer, buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
1887                                            FALSE, width, height, width, width);
1888
1889                 MEM_freeN(buffer);
1890         }
1891 }
1892
1893 void IMB_display_buffer_release(void *cache_handle)
1894 {
1895         if (cache_handle) {
1896                 BLI_lock_thread(LOCK_COLORMANAGE);
1897
1898                 colormanage_cache_handle_release(cache_handle);
1899
1900                 BLI_unlock_thread(LOCK_COLORMANAGE);
1901         }
1902 }
1903
1904 /*********************** Display functions *************************/
1905
1906 const char *colormanage_display_get_default_name(void)
1907 {
1908         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1909         const char *display_name;
1910
1911         display_name = OCIO_configGetDefaultDisplay(config);
1912
1913         OCIO_configRelease(config);
1914
1915         return display_name;
1916 }
1917
1918 ColorManagedDisplay *colormanage_display_get_default(void)
1919 {
1920         const char *display_name = colormanage_display_get_default_name();
1921
1922         if (display_name[0] == '\0')
1923                 return NULL;
1924
1925         return colormanage_display_get_named(display_name);
1926 }
1927
1928 ColorManagedDisplay *colormanage_display_add(const char *name)
1929 {
1930         ColorManagedDisplay *display;
1931         int index = 0;
1932
1933         if (global_displays.last) {
1934                 ColorManagedDisplay *last_display = global_displays.last;
1935
1936                 index = last_display->index;
1937         }
1938
1939         display = MEM_callocN(sizeof(ColorManagedDisplay), "ColorManagedDisplay");
1940
1941         display->index = index + 1;
1942
1943         BLI_strncpy(display->name, name, sizeof(display->name));
1944
1945         BLI_addtail(&global_displays, display);
1946
1947         return display;
1948 }
1949
1950 ColorManagedDisplay *colormanage_display_get_named(const char *name)
1951 {
1952         ColorManagedDisplay *display;
1953
1954         for (display = global_displays.first; display; display = display->next) {
1955                 if (!strcmp(display->name, name))
1956                         return display;
1957         }
1958
1959         return NULL;
1960 }
1961
1962 ColorManagedDisplay *colormanage_display_get_indexed(int index)
1963 {
1964         /* display indices are 1-based */
1965         return BLI_findlink(&global_displays, index - 1);
1966 }
1967
1968 int IMB_colormanagement_display_get_named_index(const char *name)
1969 {
1970         ColorManagedDisplay *display;
1971
1972         display = colormanage_display_get_named(name);
1973
1974         if (display) {
1975                 return display->index;
1976         }
1977
1978         return 0;
1979 }
1980
1981 const char *IMB_colormanagement_display_get_indexed_name(int index)
1982 {
1983         ColorManagedDisplay *display;
1984
1985         display = colormanage_display_get_indexed(index);
1986
1987         if (display) {
1988                 return display->name;
1989         }
1990
1991         return NULL;
1992 }
1993
1994 const char *IMB_colormanagement_display_get_default_name(void)
1995 {
1996         ColorManagedDisplay *display = colormanage_display_get_default();
1997
1998         return display->name;
1999 }
2000
2001 /* used by performance-critical pixel processing areas, such as color widgets */
2002 ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
2003 {
2004         return colormanage_display_get_named(name);
2005 }
2006
2007 const char *IMB_colormanagement_display_get_none_name(void)
2008 {
2009         if (colormanage_display_get_named("None") != NULL)
2010                 return "None";
2011
2012         return colormanage_display_get_default_name();
2013 }
2014
2015 /*********************** View functions *************************/
2016
2017 const char *colormanage_view_get_default_name(const ColorManagedDisplay *display)
2018 {
2019         OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2020         const char *name;
2021
2022         name = OCIO_configGetDefaultView(config, display->name);
2023
2024         OCIO_configRelease(config);
2025
2026         return name;
2027 }
2028
2029 ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display)
2030 {
2031         const char *name = colormanage_view_get_default_name(display);
2032
2033         if (!name || name[0] == '\0')
2034                 return NULL;
2035
2036         return colormanage_view_get_named(name);
2037 }
2038
2039 ColorManagedView *colormanage_view_add(const char *name)
2040 {
2041         ColorManagedView *view;
2042         int index = global_tot_view;
2043
2044         view = MEM_callocN(sizeof(ColorManagedView), "ColorManagedView");
2045         view->index = index + 1;
2046         BLI_strncpy(view->name, name, sizeof(view->name));
2047
2048         BLI_addtail(&global_views, view);
2049
2050         global_tot_view++;
2051
2052         return view;
2053 }
2054
2055 ColorManagedView *colormanage_view_get_named(const char *name)
2056 {
2057         ColorManagedView *view;
2058
2059         for (view = global_views.first; view; view = view->next) {
2060                 if (!strcmp(view->name, name))
2061                         return view;
2062         }
2063
2064         return NULL;
2065 }
2066
2067 ColorManagedView *colormanage_view_get_indexed(int index)
2068 {
2069         /* view transform indices are 1-based */
2070         return BLI_findlink(&global_views, index - 1);
2071 }
2072
2073 int IMB_colormanagement_view_get_named_index(const char *name)
2074 {
2075         ColorManagedView *view = colormanage_view_get_named(name);
2076
2077         if (view) {
2078                 return view->index;
2079         }
2080
2081         return 0;
2082 }
2083
2084 const char *IMB_colormanagement_view_get_indexed_name(int index)
2085 {
2086         ColorManagedView *view = colormanage_view_get_indexed(index);
2087
2088         if (view) {
2089                 return view->name;
2090         }
2091
2092         return NULL;
2093 }
2094
2095 const char *IMB_colormanagement_view_get_default_name(const char *display_name)
2096 {
2097         ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2098         ColorManagedView *view = NULL;
2099         
2100         if (display)
2101                 view = colormanage_view_get_default(display);
2102
2103         if (view)
2104                 return view->name;
2105
2106         return NULL;
2107 }
2108
2109 /*********************** Color space functions *************************/
2110
2111 static void colormanage_description_strip(char *description)
2112 {
2113         int i, n;
2114
2115         for (i = strlen(description) - 1; i >= 0; i--) {
2116                 if (ELEM(description[i], '\r', '\n')) {
2117                         description[i] = '\0';
2118                 }
2119                 else {
2120                         break;
2121                 }
2122         }
2123
2124         for (i = 0, n = strlen(description); i < n; i++) {
2125                 if (ELEM(description[i], '\r', '\n')) {
2126                         description[i] = ' ';
2127                 }
2128         }
2129 }
2130
2131 ColorSpace *colormanage_colorspace_add(const char *name, const char *description, int is_invertible, int is_data)
2132 {
2133         ColorSpace *colorspace, *prev_space;
2134         int counter = 1;
2135
2136         colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace");
2137
2138         BLI_strncpy(colorspace->name, name, sizeof(colorspace->name));
2139
2140         if (description) {
2141                 BLI_strncpy(colorspace->description, description, sizeof(colorspace->description));
2142
2143                 colormanage_description_strip(colorspace->description);
2144         }
2145
2146         colorspace->is_invertible = is_invertible;
2147         colorspace->is_data = is_data;
2148
2149         for (prev_space = global_colorspaces.first; prev_space; prev_space = prev_space->next) {
2150                 if (BLI_strcasecmp(prev_space->name, colorspace->name) > 0)
2151                         break;
2152
2153                 prev_space->index = counter++;
2154         }
2155
2156         if (!prev_space)
2157                 BLI_addtail(&global_colorspaces, colorspace);
2158         else
2159                 BLI_insertlinkbefore(&global_colorspaces, prev_space, colorspace);
2160
2161         colorspace->index = counter++;
2162         for (; prev_space; prev_space = prev_space->next) {
2163                 prev_space->index = counter++;
2164         }
2165
2166         global_tot_colorspace++;
2167
2168         return colorspace;
2169 }
2170
2171 ColorSpace *colormanage_colorspace_get_named(const char *name)
2172 {
2173         ColorSpace *colorspace;
2174
2175         for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
2176                 if (!strcmp(colorspace->name, name))
2177                         return colorspace;
2178         }
2179
2180         return NULL;
2181 }
2182
2183 ColorSpace *colormanage_colorspace_get_roled(int role)
2184 {
2185         const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
2186
2187         return colormanage_colorspace_get_named(role_colorspace);
2188 }
2189
2190 ColorSpace *colormanage_colorspace_get_indexed(int index)
2191 {
2192         /* display indices are 1-based */
2193         return BLI_findlink(&global_colorspaces, index - 1);
2194 }
2195
2196 int IMB_colormanagement_colorspace_get_named_index(const char *name)
2197 {
2198         ColorSpace *colorspace;
2199
2200         colorspace = colormanage_colorspace_get_named(name);
2201
2202         if (colorspace) {
2203                 return colorspace->index;
2204         }
2205
2206         return 0;
2207 }
2208
2209 const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
2210 {
2211         ColorSpace *colorspace;
2212
2213         colorspace = colormanage_colorspace_get_indexed(index);
2214
2215         if (colorspace) {
2216                 return colorspace->name;
2217         }
2218
2219         return "";
2220 }
2221
2222 void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
2223 {
2224         ImFileType *type;
2225
2226         for (type = IMB_FILE_TYPES; type->is_a; type++) {
2227                 if (type->save && type->ftype(type, ibuf)) {
2228                         const char *role_colorspace;
2229
2230                         role_colorspace = IMB_colormanagement_role_colorspace_name_get(type->default_save_role);
2231
2232                         BLI_strncpy(colorspace_settings->name, role_colorspace, sizeof(colorspace_settings->name));
2233                 }
2234         }
2235 }
2236
2237 /*********************** RNA helper functions *************************/
2238
2239 void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
2240 {
2241         ColorManagedDisplay *display;
2242
2243         for (display = global_displays.first; display; display = display->next) {
2244                 EnumPropertyItem item;
2245
2246                 item.value = display->index;
2247                 item.name = display->name;
2248                 item.identifier = display->name;
2249                 item.icon = 0;
2250                 item.description = "";
2251
2252                 RNA_enum_item_add(items, totitem, &item);
2253         }
2254 }
2255
2256 static void colormanagement_view_item_add(EnumPropertyItem **items, int *totitem, ColorManagedView *view)
2257 {
2258         EnumPropertyItem item;
2259
2260         item.value = view->index;
2261         item.name = view->name;
2262         item.identifier = view->name;
2263         item.icon = 0;
2264         item.description = "";
2265
2266         RNA_enum_item_add(items, totitem, &item);
2267 }
2268
2269 void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, const char *display_name)
2270 {
2271         ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2272         ColorManagedView *view;
2273
2274         if (display) {
2275                 LinkData *display_view;
2276
2277                 for (display_view = display->views.first; display_view; display_view = display_view->next) {
2278                         view = display_view->data;
2279
2280                         colormanagement_view_item_add(items, totitem, view);
2281                 }
2282         }
2283 }
2284
2285 void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *totitem)
2286 {
2287         ColorSpace *colorspace;
2288
2289         for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
2290                 EnumPropertyItem item;
2291
2292                 if (!colorspace->is_invertible)
2293                         continue;
2294
2295                 item.value = colorspace->index;
2296                 item.name = colorspace->name;
2297                 item.identifier = colorspace->name;
2298                 item.icon = 0;
2299
2300                 if (colorspace->description)
2301                         item.description = colorspace->description;
2302                 else
2303                         item.description = "";
2304
2305                 RNA_enum_item_add(items, totitem, &item);
2306         }
2307 }
2308
2309 /*********************** Partial display buffer update  *************************/
2310
2311 /*
2312  * Partial display update is supposed to be used by such areas as
2313  * compositor and renderer, This areas are calculating tiles of the
2314  * images and because of performance reasons only this tiles should
2315  * be color managed.
2316  * This gives nice visual feedback without slowing things down.
2317  *
2318  * Updating happens for active display transformation only, all
2319  * the rest buffers would be marked as dirty
2320  */
2321
2322 static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffer, const float *linear_buffer,
2323                                        const unsigned char *byte_buffer, int display_stride, int linear_stride,
2324                                        int linear_offset_x, int linear_offset_y, ColormanageProcessor *cm_processor,
2325                                        int xmin, int ymin, int xmax, int ymax)
2326 {
2327         int x, y;
2328         int channels = ibuf->channels;
2329         int predivide = ibuf->flags & IB_cm_predivide;
2330         float dither = ibuf->dither;
2331         ColorSpace *rect_colorspace = ibuf->rect_colorspace;
2332         float *display_buffer_float = NULL;
2333         int width = xmax - xmin;
2334         int height = ymax - ymin;
2335         int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
2336
2337         if (dither != 0.0f) {
2338                 display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither");
2339         }
2340
2341         for (y = ymin; y < ymax; y++) {
2342                 for (x = xmin; x < xmax; x++) {
2343                         int display_index = (y * display_stride + x) * channels;
2344                         int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
2345                         float pixel[4];
2346
2347                         if (linear_buffer) {
2348                                 copy_v4_v4(pixel, (float *) linear_buffer + linear_index);
2349                         }
2350                         else if (byte_buffer) {
2351                                 rgba_uchar_to_float(pixel, byte_buffer + linear_index);
2352                                 IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
2353                         }
2354
2355                         if (!is_data) {
2356                                 if (predivide)
2357                                         IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2358                                 else
2359                                         IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2360                         }
2361
2362                         if (display_buffer_float) {
2363                                 int index = ((y - ymin) * width + (x - xmin)) * channels;
2364
2365                                 copy_v4_v4(display_buffer_float + index, pixel);
2366                         }
2367                         else {
2368                                 rgba_float_to_uchar(display_buffer + display_index, pixel);
2369                         }
2370                 }
2371         }
2372
2373         if (display_buffer_float) {
2374                 int display_index = (ymin * display_stride + xmin) * channels;
2375
2376                 IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither,
2377                                            IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, width, height, display_stride, width);
2378
2379                 MEM_freeN(display_buffer_float);
2380         }
2381 }
2382
2383 void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer,
2384                                        int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings,
2385                                        const ColorManagedDisplaySettings *display_settings,
2386                                        int xmin, int ymin, int xmax, int ymax, int update_orig_byte_buffer)
2387 {
2388         if ((ibuf->rect && ibuf->rect_float) || update_orig_byte_buffer) {
2389                 /* update byte buffer created by legacy color management */
2390
2391                 unsigned char *rect = (unsigned char *) ibuf->rect;
2392                 int predivide = ibuf->flags & IB_cm_predivide;
2393                 int channels = ibuf->channels;
2394                 int width = xmax - xmin;
2395                 int height = ymax - ymin;
2396                 int rect_index = (ymin * ibuf->x + xmin) * channels;
2397                 int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels;
2398
2399                 IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither,
2400                                            IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, width, height, ibuf->x, stride);
2401         }
2402
2403         if (ibuf->display_buffer_flags) {
2404                 ColormanageCacheViewSettings cache_view_settings;
2405                 ColormanageCacheDisplaySettings cache_display_settings;
2406                 void *cache_handle = NULL;
2407                 unsigned char *display_buffer = NULL;
2408                 int view_flag, display_index, buffer_width;
2409
2410                 colormanage_view_settings_to_cache(&cache_view_settings, view_settings);
2411                 colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
2412
2413                 view_flag = 1 << (cache_view_settings.view - 1);
2414                 display_index = cache_display_settings.display - 1;
2415
2416                 BLI_lock_thread(LOCK_COLORMANAGE);
2417                 if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0)
2418                         display_buffer = colormanage_cache_get(ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
2419
2420                 /* in some rare cases buffer's dimension could be changing directly from
2421                  * different thread
2422                  * this i.e. happens when image editor acquires render result
2423                  */
2424                 buffer_width = ibuf->x;
2425
2426                 /* mark all other buffers as invalid */
2427                 memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
2428                 ibuf->display_buffer_flags[display_index] |= view_flag;
2429
2430                 BLI_unlock_thread(LOCK_COLORMANAGE);
2431
2432                 if (display_buffer) {
2433                         ColormanageProcessor *cm_processor;
2434
2435                         cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2436
2437                         partial_buffer_update_rect(ibuf, display_buffer, linear_buffer, byte_buffer, buffer_width, stride,
2438                                                    offset_x, offset_y, cm_processor, xmin, ymin, xmax, ymax);
2439
2440                         IMB_colormanagement_processor_free(cm_processor);
2441
2442                         IMB_display_buffer_release(cache_handle);
2443                 }
2444         }
2445 }
2446
2447 /*********************** Pixel processor functions *************************/
2448
2449 ColormanageProcessor *IMB_colormanagement_display_processor_new(const ColorManagedViewSettings *view_settings,
2450                                                                 const ColorManagedDisplaySettings *display_settings)
2451 {
2452         ColormanageProcessor *cm_processor;
2453         ColorManagedViewSettings default_view_settings;
2454         const ColorManagedViewSettings *applied_view_settings;
2455         ColorSpace *display_space;
2456
2457         cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
2458
2459         if (view_settings) {
2460                 applied_view_settings = view_settings;
2461         }
2462         else {
2463                 init_default_view_settings(display_settings,  &default_view_settings);
2464                 applied_view_settings = &default_view_settings;
2465         }
2466
2467         display_space =  display_transform_get_colorspace(applied_view_settings, display_settings);
2468         cm_processor->is_data_result = display_space->is_data;
2469
2470         cm_processor->processor = create_display_buffer_processor(applied_view_settings->view_transform, display_settings->display_device,
2471                                                                   applied_view_settings->exposure, applied_view_settings->gamma);
2472
2473         if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
2474                 cm_processor->curve_mapping = curvemapping_copy(applied_view_settings->curve_mapping);
2475                 curvemapping_premultiply(cm_processor->curve_mapping, FALSE);
2476         }
2477
2478         return cm_processor;
2479 }
2480
2481 ColormanageProcessor *IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
2482 {
2483         ColormanageProcessor *cm_processor;
2484         ColorSpace *color_space;
2485
2486         cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
2487
2488         color_space = colormanage_colorspace_get_named(to_colorspace);
2489         cm_processor->is_data_result = color_space->is_data;
2490
2491         cm_processor->processor = create_colorspace_transform_processor(from_colorspace, to_colorspace);
2492
2493         return cm_processor;
2494 }
2495
2496 void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, float pixel[4])
2497 {
2498         if (cm_processor->curve_mapping)
2499                 curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
2500
2501         if (cm_processor->processor)
2502                 OCIO_processorApplyRGBA(cm_processor->processor, pixel);
2503 }
2504
2505 void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3])
2506 {
2507         if (cm_processor->curve_mapping)
2508                 curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
2509
2510         if (cm_processor->processor)
2511                 OCIO_processorApplyRGB(cm_processor->processor, pixel);
2512 }
2513
2514 void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, float *buffer, int width, int height,
2515                                          int channels, int predivide)
2516 {
2517         /* apply curve mapping */
2518         if (cm_processor->curve_mapping) {
2519                 int x, y;
2520
2521                 for (y = 0; y < height; y++) {
2522                         for (x = 0; x < width; x++) {
2523                                 float *pixel = buffer + channels * (y * width + x);
2524
2525                                 curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
2526                         }
2527                 }
2528         }
2529
2530         if (cm_processor->processor && channels >= 3) {
2531                 OCIO_PackedImageDesc *img;
2532
2533                 /* apply OCIO processor */
2534                 img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
2535                                                  channels * sizeof(float), channels * sizeof(float) * width);
2536
2537                 if (predivide)
2538                         OCIO_processorApply_predivide(cm_processor->processor, img);
2539                 else
2540                         OCIO_processorApply(cm_processor->processor, img);
2541
2542                 OCIO_OCIO_PackedImageDescRelease(img);
2543         }
2544 }
2545
2546 void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
2547 {
2548         if (cm_processor->curve_mapping)
2549                 curvemapping_free(cm_processor->curve_mapping);
2550         if (cm_processor->processor)
2551                 OCIO_processorRelease(cm_processor->processor);
2552
2553         MEM_freeN(cm_processor);
2554 }