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