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