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