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