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