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