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