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