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