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