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