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