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