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