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