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