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