Color management: added view transforms form nuke-default and spi-vfx
[blender.git] / source / blender / imbuf / intern / colormanagement.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2012 by Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Xavier Thomas,
24  *                 Lukas Toenne,
25  *                 Sergey Sharybin
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 #include "IMB_colormanagement.h"
32 #include "IMB_colormanagement_intern.h"
33
34 #include <string.h>
35 #include <math.h>
36
37 #include "DNA_color_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_windowmanager_types.h"
41
42 #include "IMB_filter.h"
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
45 #include "IMB_moviecache.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_math.h"
51 #include "BLI_math_color.h"
52 #include "BLI_path_util.h"
53 #include "BLI_string.h"
54 #include "BLI_threads.h"
55
56 #include "BKE_utildefines.h"
57 #include "BKE_main.h"
58
59 #include "RNA_define.h"
60
61 #ifdef WITH_OCIO
62 #  include <ocio_capi.h>
63 #endif
64
65 /*********************** Global declarations *************************/
66
67 /* ** list of all supported color spaces, displays and views */
68 #ifdef WITH_OCIO
69 static ListBase global_colorspaces = {NULL};
70
71 static char global_role_linear[64];
72 static char global_role_color_picking[64];
73 static char global_role_texture_painting[64];
74
75 #endif
76
77 static ListBase global_displays = {NULL};
78 static ListBase global_views = {NULL};
79
80 static int global_tot_display = 0;
81 static int global_tot_view = 0;
82
83 /*********************** Color managed cache *************************/
84
85 /* Currently it's original ImBuf pointer is used to distinguish which
86  * datablock, frame number, possible postprocessing display buffer was
87  * created for.
88  *
89  * This makes it's possible to easy define key for color managed cache
90  * which would work for Images, Movie Clips, Sequencer Strips and so.
91  *
92  * This also allows to easily control memory usage -- all color managed
93  * buffers are concentrated in single cache and it's really easy to
94  * control maximal memory usage for all color management related stuff
95  * (currently supports only maximal memory usage, but it could be
96  * improved further to support removing buffers when they are not needed
97  * anymore but memory usage didn't exceed it's limit).
98  *
99  * This ImBuf is being referenced by cache key, so it could accessed
100  * anytime on runtime while cache element is valid. This is needed to
101  * support removing display buffers from cache when ImBuf they were
102  * created for is being freed.
103  *
104  * Technically it works in the following way:
105  * - ImBuf is being referenced first time when display buffer is
106  *   creating for it and being put into the cache
107  * - On any further display buffer created for this ImBuf user
108  *   reference counter is not being incremented
109  * - There's count of color management users in ImBuf which is
110  *   being incremented every time display buffer is creating for
111  *   giver ImBuf.
112  * - Hence, we always know how many display buffers is created
113  *   for the ImBuf and if there's any display buffers created
114  *   this ImBuf would be referenced by color management stuff and
115  *   actual data for it wouldn't be freed even when this ImBuf is
116  *   being freed by user, who created it.
117  * - When all external users finished working with this ImBuf it's
118  *   reference counter would be 0.
119  * - On every new display buffer adding to the cache review of
120  *   the cache happens and all cached display buffers who's ImBuf's
121  *   user counter is zero are being removed from the cache.
122  * - On every display buffer removed from the cache ImBuf's color
123  *   management user counter is being decremented. As soon as it's
124  *   becoming zero, original ImBuf is being freed completely.
125  */
126
127 typedef struct ColormanageCacheKey {
128         ImBuf *ibuf;         /* image buffer for which display buffer was created */
129         int view_transform;  /* view transformation used for display buffer */
130         int display;         /* display device name */
131 } ColormanageCacheKey;
132
133 typedef struct ColormnaageCacheImBufData {
134         float exposure;  /* exposure value cached buffer is calculated with */
135         float gamma;     /* gamma value cached buffer is calculated with */
136 } ColormnaageCacheImBufData;
137
138 static struct MovieCache *colormanage_cache = NULL;
139
140 static unsigned int colormanage_hashhash(const void *key_v)
141 {
142         ColormanageCacheKey *key = (ColormanageCacheKey *)key_v;
143
144         unsigned int rval = *(unsigned int *) key->ibuf;
145
146         return rval;
147 }
148
149 static int colormanage_hashcmp(const void *av, const void *bv)
150 {
151         const ColormanageCacheKey *a = (ColormanageCacheKey *) av;
152         const ColormanageCacheKey *b = (ColormanageCacheKey *) bv;
153
154         if (a->ibuf < b->ibuf)
155                 return -1;
156         else if (a->ibuf > b->ibuf)
157                 return 1;
158
159         if (a->view_transform < b->view_transform)
160                 return -1;
161         else if (a->view_transform > b->view_transform)
162                 return 1;
163
164         if (a->display < b->display)
165                 return -1;
166         else if (a->display > b->display)
167                 return 1;
168
169         return 0;
170 }
171
172 static int colormanage_checkkeyunused(void *key_v)
173 {
174         ColormanageCacheKey *key = (ColormanageCacheKey *)key_v;
175
176         return key->ibuf->refcounter == 0;
177 }
178
179 static void colormanage_keydeleter(void *key_v)
180 {
181         ColormanageCacheKey *key = (ColormanageCacheKey *)key_v;
182         ImBuf *cache_ibuf = key->ibuf;
183
184         cache_ibuf->colormanage_refcounter--;
185
186         if (cache_ibuf->colormanage_refcounter == 0) {
187                 IMB_freeImBuf(key->ibuf);
188         }
189 }
190
191 static void colormanage_cache_init(void)
192 {
193         colormanage_cache = IMB_moviecache_create(sizeof(ColormanageCacheKey), colormanage_keydeleter,
194                                                   colormanage_hashhash, colormanage_hashcmp,
195                                                   NULL, colormanage_checkkeyunused);
196 }
197
198 static void colormanage_cache_exit(void)
199 {
200         IMB_moviecache_free(colormanage_cache);
201 }
202
203 #ifdef WITH_OCIO
204 static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf, int view_transform, int display, void **cache_handle)
205 {
206         ImBuf *cache_ibuf;
207         ColormanageCacheKey key;
208
209         *cache_handle = NULL;
210
211         key.ibuf = ibuf;
212         key.view_transform = view_transform;
213         key.display = display;
214
215         cache_ibuf = IMB_moviecache_get(colormanage_cache, &key);
216
217         *cache_handle = cache_ibuf;
218
219         return cache_ibuf;
220 }
221
222 static unsigned char *colormanage_cache_get(ImBuf *ibuf, int view_transform, int display,
223                                             float exposure, float gamma, void **cache_handle)
224 {
225         ImBuf *cache_ibuf = colormanage_cache_get_ibuf(ibuf, view_transform, display, cache_handle);
226
227         if (cache_ibuf) {
228                 ColormnaageCacheImBufData *cache_data;
229
230                 /* only buffers with different color space conversions are being stored
231                  * in cache separately. buffer which were used only different exposure/gamma
232                  * are re-suing the same cached buffer
233                  *
234                  * check here which exposure/gamma was used for cached buffer and if they're
235                  * different from requested buffer should be re-generated
236                  */
237                 cache_data = (ColormnaageCacheImBufData *) cache_ibuf->colormanage_cache_data;
238                 if (cache_data->exposure != exposure || cache_data->gamma != gamma) {
239                         IMB_freeImBuf(cache_ibuf);
240
241                         return NULL;
242                 }
243
244                 return (unsigned char *) cache_ibuf->rect;
245         }
246
247         return NULL;
248 }
249
250 static void colormanage_cache_put(ImBuf *ibuf, int view_transform, int display, float exposure, float gamma,
251                                   unsigned char *display_buffer, void **cache_handle)
252 {
253         ColormanageCacheKey key;
254         ImBuf *cache_ibuf;
255         ColormnaageCacheImBufData *cache_data;
256
257         key.ibuf = ibuf;
258         key.view_transform = view_transform;
259         key.display = display;
260
261         /* buffer itself */
262         cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
263         cache_ibuf->rect = (unsigned int *) display_buffer;
264
265         cache_ibuf->mall |= IB_rect;
266         cache_ibuf->flags |= IB_rect;
267
268         /* store data which is needed to check whether cached buffer could be used for color managed display settings */
269         cache_data = MEM_callocN(sizeof(ColormnaageCacheImBufData), "color manage cache imbuf data");
270         cache_data->exposure = exposure;
271         cache_data->gamma = gamma;
272
273         cache_ibuf->colormanage_cache_data = cache_data;
274
275         *cache_handle = cache_ibuf;
276
277         /* mark source buffer as having color managed buffer and increment color managed buffers count for it */
278         if ((ibuf->colormanage_flags & IMB_COLORMANAGED) == 0) {
279                 ibuf->colormanage_flags |= IMB_COLORMANAGED;
280
281                 IMB_refImBuf(ibuf);
282         }
283
284         ibuf->colormanage_refcounter++;
285
286         IMB_moviecache_put(colormanage_cache, &key, cache_ibuf);
287 }
288
289 /* validation function checks whether there's buffer with given display transform
290  * in the cache and if so, check whether it matches resolution of source buffer.
291  * if resolution is different new buffer would be put into the cache and it'll
292  * be returned as a result
293  *
294  * this function does not check exposure / gamma because currently it's only
295  * used by partial buffer update functions which uses the same exposure / gamma
296  * settings as cached buffer had
297  */
298 static unsigned char *colormanage_cache_get_validated(ImBuf *ibuf, int view_transform, int display, void **cache_handle)
299 {
300         ImBuf *cache_ibuf = colormanage_cache_get_ibuf(ibuf, view_transform, display, cache_handle);
301
302         if (cache_ibuf) {
303                 if (cache_ibuf->x != ibuf->x || cache_ibuf->y != ibuf->y) {
304                         ColormnaageCacheImBufData *cache_data;
305                         unsigned char *display_buffer;
306                         int buffer_size;
307
308                         /* use the same settings as original cached buffer  */
309                         cache_data = (ColormnaageCacheImBufData *) cache_ibuf->colormanage_cache_data;
310
311                         buffer_size = ibuf->channels * ibuf->x * ibuf->y * sizeof(float);
312                         display_buffer = MEM_callocN(buffer_size, "imbuf validated display buffer");
313
314                         colormanage_cache_put(ibuf, view_transform, display, cache_data->exposure, cache_data->gamma,
315                                               display_buffer, cache_handle);
316
317                         IMB_freeImBuf(cache_ibuf);
318
319                         return display_buffer;
320                 }
321
322                 return (unsigned char *) cache_ibuf->rect;
323         }
324
325         return NULL;
326 }
327
328 /* return view settings which are stored in cached buffer, not in key itself */
329 static void colormanage_cache_get_cache_data(void *cache_handle, float *exposure, float *gamma)
330 {
331         ImBuf *cache_ibuf = (ImBuf *) cache_handle;
332         ColormnaageCacheImBufData *cache_data;
333
334         cache_data = (ColormnaageCacheImBufData *) cache_ibuf->colormanage_cache_data;
335
336         *exposure = cache_data->exposure;
337         *gamma = cache_data->gamma;
338 }
339 #endif
340
341 static void colormanage_cache_handle_release(void *cache_handle)
342 {
343         ImBuf *cache_ibuf = cache_handle;
344
345         IMB_freeImBuf(cache_ibuf);
346 }
347
348 /*********************** Initialization / De-initialization *************************/
349
350 #ifdef WITH_OCIO
351 static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char *colorspace_name, int max_colorspace_name,
352                                                   const char *role, const char *role_name)
353 {
354         ConstColorSpaceRcPtr *ociocs;
355
356         ociocs = OCIO_configGetColorSpace(config, role);
357
358         if (ociocs) {
359                 const char *name = OCIO_colorSpaceGetName(ociocs);
360
361                 BLI_strncpy(colorspace_name, name, max_colorspace_name);
362                 OCIO_colorSpaceRelease(ociocs);
363         }
364         else {
365                 printf("Blender color management: Error could not find %s role.\n", role_name);
366         }
367 }
368
369 static void colormanage_load_config(ConstConfigRcPtr *config)
370 {
371         ConstColorSpaceRcPtr *ociocs;
372         int tot_colorspace, tot_display, tot_display_view, index, viewindex, viewindex2;
373         const char *name;
374
375         /* get roles */
376         colormanage_role_color_space_name_get(config, global_role_linear, sizeof(global_role_linear),
377                                               OCIO_ROLE_SCENE_LINEAR, "scene linear");
378
379         colormanage_role_color_space_name_get(config, global_role_color_picking, sizeof(global_role_color_picking),
380                                               OCIO_ROLE_COLOR_PICKING, "color picking");
381
382         colormanage_role_color_space_name_get(config, global_role_texture_painting, sizeof(global_role_texture_painting),
383                                               OCIO_ROLE_TEXTURE_PAINT, "texture_painting");
384
385         /* load colorspaces */
386         tot_colorspace = OCIO_configGetNumColorSpaces(config);
387         for (index = 0 ; index < tot_colorspace; index++) {
388                 ColorSpace *colorspace;
389
390                 name = OCIO_configGetColorSpaceNameByIndex(config, index);
391                 ociocs = OCIO_configGetColorSpace(config, name);
392
393                 colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace");
394                 colorspace->index = index + 1;
395
396                 BLI_strncpy(colorspace->name, name, sizeof(colorspace->name));
397
398                 BLI_addtail(&global_colorspaces, colorspace);
399
400                 OCIO_colorSpaceRelease(ociocs);
401         }
402
403         /* load displays */
404         viewindex2 = 0;
405         tot_display = OCIO_configGetNumDisplays(config);
406
407         for (index = 0 ; index < tot_display; index++) {
408                 const char *displayname;
409                 ColorManagedDisplay *display;
410
411                 displayname = OCIO_configGetDisplay(config, index);
412
413                 display = colormanage_display_add(displayname);
414
415                 /* load views */
416                 tot_display_view = OCIO_configGetNumViews(config, displayname);
417                 for (viewindex = 0 ; viewindex < tot_display_view; viewindex++, viewindex2++) {
418                         const char *viewname;
419                         ColorManagedView *view;
420                         LinkData *display_view;
421
422                         viewname = OCIO_configGetView(config, displayname, viewindex);
423
424                         /* first check if view transform with given name was already loaded */
425                         view = colormanage_view_get_named(viewname);
426
427                         if (!view) {
428                                 view = colormanage_view_add(viewname);
429                         }
430
431                         display_view = BLI_genericNodeN(view);
432
433                         BLI_addtail(&display->views, display_view);
434                 }
435         }
436
437         global_tot_display = tot_display;
438 }
439
440 void colormanage_free_config(void)
441 {
442         ColorSpace *colorspace;
443         ColorManagedDisplay *display;
444         ColorManagedView *view;
445
446         colorspace = global_colorspaces.first;
447         while (colorspace) {
448                 ColorSpace *colorspace_next = colorspace->next;
449
450                 MEM_freeN(colorspace);
451                 colorspace = colorspace_next;
452         }
453
454         display = global_displays.first;
455         while (display) {
456                 ColorManagedDisplay *display_next = display->next;
457                 LinkData *display_view = display->views.first;
458
459                 while (display_view) {
460                         LinkData *display_view_next = display_view->next;
461
462                         MEM_freeN(display_view);
463                         display_view = display_view_next;
464                 }
465
466                 MEM_freeN(display);
467                 display = display_next;
468         }
469
470         view = global_views.first;
471         while (view) {
472                 ColorManagedView *view_next = view->next;
473
474                 MEM_freeN(view);
475                 view = view_next;
476         }
477 }
478 #endif
479
480 void IMB_colormanagement_init(void)
481 {
482 #ifdef WITH_OCIO
483         const char *ocio_env;
484         const char *configdir;
485         char configfile[FILE_MAX];
486         ConstConfigRcPtr *config = NULL;
487
488         ocio_env = getenv("OCIO");
489
490         if (ocio_env) {
491                 config = OCIO_configCreateFromEnv();
492         }
493         else {
494                 configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement");
495
496                 if (configdir)  {
497                         BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
498
499                         config = OCIO_configCreateFromFile(configfile);
500                 }
501         }
502
503         if (config) {
504                 OCIO_setCurrentConfig(config);
505
506                 colormanage_load_config(config);
507         }
508
509         OCIO_configRelease(config);
510
511         /* special views, which does not depend on OCIO  */
512         colormanage_view_add("ACES ODT Tonecurve");
513 #endif
514
515         colormanage_cache_init();
516 }
517
518 void IMB_colormanagement_exit(void)
519 {
520 #ifdef WITH_OCIO
521         colormanage_free_config();
522 #endif
523
524         colormanage_cache_exit();
525 }
526
527 /*********************** Public display buffers interfaces *************************/
528
529 #ifdef WITH_OCIO
530 typedef struct DisplayBufferThread {
531         void *processor;
532
533         float *buffer;
534         unsigned char *display_buffer;
535
536         int width;
537         int start_line;
538         int tot_line;
539
540         int channels;
541         int dither;
542         int predivide;
543 } DisplayBufferThread;
544
545 static void display_buffer_apply_threaded(ImBuf *ibuf, float *buffer, unsigned char *display_buffer,
546                                           void *processor, void *(do_thread) (void *))
547 {
548         DisplayBufferThread handles[BLENDER_MAX_THREADS];
549         ListBase threads;
550
551         int predivide = ibuf->flags & IB_cm_predivide;
552         int i, tot_thread = BLI_system_thread_count();
553         int start_line, tot_line;
554
555         BLI_init_threads(&threads, do_thread, tot_thread);
556
557         start_line = 0;
558         tot_line = ((float)(ibuf->y / tot_thread)) + 0.5f;
559
560         for (i = 0; i < tot_thread; i++) {
561                 int offset = ibuf->channels * start_line * ibuf->x;
562
563                 handles[i].processor = processor;
564
565                 handles[i].buffer = buffer + offset;
566                 handles[i].display_buffer = display_buffer + offset;
567                 handles[i].width = ibuf->x;
568
569                 handles[i].start_line = start_line;
570
571                 if (i < tot_thread - 1) {
572                         handles[i].tot_line = tot_line;
573                 }
574                 else {
575                         handles[i].tot_line = ibuf->y - start_line;
576                 }
577
578                 handles[i].channels = ibuf->channels;
579                 handles[i].dither = ibuf->dither;
580                 handles[i].predivide = predivide;
581
582                 if (tot_thread > 1)
583                         BLI_insert_thread(&threads, &handles[i]);
584
585                 start_line += tot_line;
586         }
587
588         if (tot_thread > 1)
589                 BLI_end_threads(&threads);
590         else
591                 do_thread(&handles[0]);
592 }
593
594 static void *do_display_buffer_apply_tonemap_thread(void *handle_v)
595 {
596         DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
597         imb_tonecurveCb tonecurve_func = (imb_tonecurveCb) handle->processor;
598
599         float *buffer = handle->buffer;
600         unsigned char *display_buffer = handle->display_buffer;
601
602         int channels = handle->channels;
603         int width = handle->width;
604         int height = handle->tot_line;
605         int dither = handle->dither;
606         int predivide = handle->predivide;
607
608         IMB_buffer_byte_from_float_tonecurve(display_buffer, buffer, channels, dither,
609                                              IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
610                                              predivide, width, height, width, width,
611                                                                                  tonecurve_func);
612
613         return NULL;
614 }
615
616 static void display_buffer_apply_tonemap(ImBuf *ibuf, unsigned char *display_buffer,
617                                          imb_tonecurveCb tonecurve_func)
618 {
619         display_buffer_apply_threaded(ibuf, ibuf->rect_float, display_buffer, tonecurve_func,
620                                       do_display_buffer_apply_tonemap_thread);
621 }
622
623 static void *do_display_buffer_apply_ocio_thread(void *handle_v)
624 {
625         DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
626         ConstProcessorRcPtr *processor = (ConstProcessorRcPtr *) handle->processor;
627         PackedImageDesc *img;
628         float *buffer = handle->buffer;
629         unsigned char *display_buffer = handle->display_buffer;
630         int channels = handle->channels;
631         int width = handle->width;
632         int height = handle->tot_line;
633         int dither = handle->dither;
634         int predivide = handle->predivide;
635
636         img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float),
637                                          channels * sizeof(float), channels * sizeof(float) * width);
638
639         OCIO_processorApply(processor, img);
640
641         OCIO_packedImageDescRelease(img);
642
643         /* do conversion */
644         IMB_buffer_byte_from_float(display_buffer, buffer,
645                                    channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
646                                                            predivide, width, height, width, width);
647
648         return NULL;
649 }
650
651 static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display,
652                                                             float exposure, float gamma)
653 {
654         ConstConfigRcPtr *config = OCIO_getCurrentConfig();
655         DisplayTransformRcPtr *dt;
656         ExponentTransformRcPtr *et;
657         MatrixTransformRcPtr *mt;
658         ConstProcessorRcPtr *processor;
659
660         float exponent = 1.0f / MAX2(FLT_EPSILON, gamma);
661         const float exponent4f[] = {exponent, exponent, exponent, exponent};
662
663         float gain = powf(2.0f, exposure);
664         const float scale4f[] = {gain, gain, gain, gain};
665         float m44[16], offset4[4];
666
667         if (!config) {
668                 /* there's no valid OCIO configuration, can't create processor */
669
670                 return NULL;
671         }
672
673         dt = OCIO_createDisplayTransform();
674
675         /* OCIO_TODO: get rid of hardcoded input space */
676         OCIO_displayTransformSetInputColorSpaceName(dt, global_role_linear);
677
678         OCIO_displayTransformSetView(dt, view_transform);
679         OCIO_displayTransformSetDisplay(dt, display);
680
681         /* fstop exposure control */
682         OCIO_matrixTransformScale(m44, offset4, scale4f);
683         mt = OCIO_createMatrixTransform();
684         OCIO_matrixTransformSetValue(mt, m44, offset4);
685         OCIO_displayTransformSetLinearCC(dt, (ConstTransformRcPtr *) mt);
686
687         /* post-display gamma transform */
688         et = OCIO_createExponentTransform();
689         OCIO_exponentTransformSetValue(et, exponent4f);
690         OCIO_displayTransformSetDisplayCC(dt, (ConstTransformRcPtr *) et);
691
692         processor = OCIO_configGetProcessor(config, (ConstTransformRcPtr *) dt);
693
694         OCIO_exponentTransformRelease(et);
695         OCIO_displayTransformRelease(dt);
696         OCIO_configRelease(config);
697
698         return processor;
699 }
700
701 static void display_buffer_apply_ocio(ImBuf *ibuf, unsigned char *display_buffer,
702                                       const ColorManagedViewSettings *view_settings,
703                                       const char *display)
704 {
705         ConstProcessorRcPtr *processor;
706         const float gamma = view_settings->gamma;
707         const float exposure = view_settings->exposure;
708         const char *view_transform = view_settings->view_transform;
709         float *rect_float;
710
711         rect_float = MEM_dupallocN(ibuf->rect_float);
712
713         processor = create_display_buffer_processor(view_transform, display, exposure, gamma);
714
715         if (processor) {
716                 display_buffer_apply_threaded(ibuf, rect_float, display_buffer, processor,
717                                               do_display_buffer_apply_ocio_thread);
718         }
719
720         OCIO_processorRelease(processor);
721
722         MEM_freeN(rect_float);
723 }
724 #endif
725
726 void IMB_colormanage_flags_allocate(ImBuf *ibuf)
727 {
728         if (global_tot_display == 0)
729                 return;
730
731         ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display, "imbuf display_buffer_flags");
732 }
733
734 void IMB_colormanage_flags_free(ImBuf *ibuf)
735 {
736         if (ibuf->display_buffer_flags) {
737                 MEM_freeN(ibuf->display_buffer_flags);
738
739                 ibuf->display_buffer_flags = NULL;
740         }
741 }
742
743 void IMB_colormanage_cache_data_free(ImBuf *ibuf)
744 {
745         if (ibuf->colormanage_cache_data) {
746                 MEM_freeN(ibuf->colormanage_cache_data);
747
748                 ibuf->colormanage_cache_data = NULL;
749         }
750 }
751
752 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
753                                           const char *display, void **cache_handle)
754 {
755         const char *view_transform = view_settings->view_transform;
756
757         *cache_handle = NULL;
758
759 #ifdef WITH_OCIO
760
761         if (!ibuf->x || !ibuf->y)
762                 return NULL;
763
764         /* OCIO_TODO: support colormanaged byte buffers */
765         if (!strcmp(view_transform, "NONE") ||
766             !ibuf->rect_float ||
767             global_tot_display == 0 ||
768             global_tot_view == 0)
769         {
770                 /* currently only view-transformation is allowed, input and display
771                  * spaces are hard-coded, so if there's no view transform applying
772                  * it's safe to suppose standard byte buffer is used for display
773                  */
774
775                 if (!ibuf->rect)
776                         IMB_rect_from_float(ibuf);
777
778                 return (unsigned char *) ibuf->rect;
779         }
780         else {
781                 unsigned char *display_buffer;
782                 int buffer_size;
783                 int view_transform_index = IMB_colormanagement_view_get_named_index(view_transform);
784                 int display_index = IMB_colormanagement_display_get_named_index(display);
785                 int view_transform_flag = 1 << (view_transform_index - 1);
786
787                 float exposure = view_settings->exposure;
788                 float gamma = view_settings->gamma;
789
790                 /* ensure color management bit fields exists */
791                 if (!ibuf->display_buffer_flags)
792                         IMB_colormanage_flags_allocate(ibuf);
793
794                 /* check whether display buffer isn't marked as dirty and if so try to get buffer from cache */
795                 if (ibuf->display_buffer_flags[display_index - 1] & view_transform_flag) {
796                         display_buffer = colormanage_cache_get(ibuf, view_transform_index, display_index,
797                                                                exposure, gamma, cache_handle);
798
799                         if (display_buffer) {
800                                 return display_buffer;
801                         }
802                 }
803
804                 /* OCIO_TODO: in case when image is being resized it is possible
805                  *            to save buffer allocation here
806                  *
807                  *            actually not because there might be other users of
808                  *            that buffer which better not to change
809                  */
810
811                 buffer_size = ibuf->channels * ibuf->x * ibuf->y * sizeof(float);
812                 display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
813
814                 if (!strcmp(view_transform, "ACES ODT Tonecurve")) {
815                         /* special case for Mango team, this does not actually apply
816                          * any input space -> display space conversion and just applies
817                          * a tonecurve for better linear float -> sRGB byte conversion
818                          */
819                         display_buffer_apply_tonemap(ibuf, display_buffer, IMB_ratio_preserving_odt_tonecurve);
820                 }
821                 else {
822                         display_buffer_apply_ocio(ibuf, display_buffer, view_settings, display);
823                 }
824
825                 colormanage_cache_put(ibuf, view_transform_index, display_index, exposure, gamma,
826                                       display_buffer, cache_handle);
827
828                 ibuf->display_buffer_flags[display_index - 1] |= view_transform_flag;
829
830                 return display_buffer;
831         }
832 #else
833         /* no OCIO support, simply return byte buffer which was
834          * generated from float buffer (if any) using standard
835          * profiles without applying any view / display transformation */
836
837         (void) view_settings;
838         (void) view_transform;
839         (void) display;
840
841         if (!ibuf->rect) {
842                 IMB_rect_from_float(ibuf);
843         }
844
845         return (unsigned char*) ibuf->rect;
846 #endif
847 }
848
849 void IMB_display_buffer_release(void *cache_handle)
850 {
851         if (cache_handle) {
852                 colormanage_cache_handle_release(cache_handle);
853         }
854 }
855
856 void IMB_display_buffer_invalidate(ImBuf *ibuf)
857 {
858         /* if there's no display_buffer_flags this means there's no color managed
859          * buffers created for this imbuf, no need to invalidate
860          */
861         if (ibuf->display_buffer_flags) {
862                 memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
863         }
864 }
865
866 #ifdef WITH_OCIO
867 static void colormanage_check_view_settings(ColorManagedViewSettings *view_settings, const char *editor,
868                                             const ColorManagedView *default_view)
869 {
870         if (view_settings->view_transform[0] == '\0') {
871                 BLI_strncpy(view_settings->view_transform, "NONE", sizeof(view_settings->view_transform));
872         }
873         else if (!strcmp(view_settings->view_transform, "NONE")) {
874                 /* pass */
875         }
876         else {
877                 ColorManagedView *view = colormanage_view_get_named(view_settings->view_transform);
878
879                 if (!view) {
880                         printf("Blender color management: %s view \"%s\" not found, setting default \"%s\".\n",
881                                editor, view_settings->view_transform, default_view->name);
882
883                         BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
884                 }
885         }
886
887         /* OCIO_TODO: move to do_versions() */
888         if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
889                 view_settings->flag |= COLORMANAGE_VIEW_USE_GLOBAL;
890                 view_settings->exposure = 0.0f;
891                 view_settings->gamma = 1.0f;
892         }
893 }
894 #endif
895
896 void IMB_colormanagement_check_file_config(Main *bmain)
897 {
898 #ifdef WITH_OCIO
899         wmWindowManager *wm = bmain->wm.first;
900         wmWindow *win;
901         bScreen *sc;
902
903         ColorManagedDisplay *default_display;
904         ColorManagedView *default_view;
905
906         default_display = colormanage_display_get_default();
907
908         if (!default_display) {
909                 /* happens when OCIO configuration is incorrect */
910                 return;
911         }
912
913         default_view = colormanage_view_get_default(default_display);
914
915         if (!default_view) {
916                 /* happens when OCIO configuration is incorrect */
917                 return;
918         }
919
920         if (wm) {
921                 for (win = wm->windows.first; win; win = win->next) {
922                         if (win->display_device[0] == '\0') {
923                                 BLI_strncpy(win->display_device, default_display->name, sizeof(win->display_device));
924                         }
925                         else {
926                                 ColorManagedDisplay *display = colormanage_display_get_named(win->display_device);
927
928                                 if (!display) {
929                                         printf("Blender color management: Window display \"%s\" not found, setting to default (\"%s\").\n",
930                                                    win->display_device, default_display->name);
931
932                                         BLI_strncpy(win->display_device, default_display->name, sizeof(win->display_device));
933                                 }
934                         }
935
936                         colormanage_check_view_settings(&win->view_settings, "window", default_view);
937                 }
938         }
939
940         for(sc = bmain->screen.first; sc; sc= sc->id.next) {
941                 ScrArea *sa;
942
943                 for (sa = sc->areabase.first; sa; sa = sa->next) {
944                         SpaceLink *sl;
945                         for (sl = sa->spacedata.first; sl; sl = sl->next) {
946
947                                 if (sl->spacetype == SPACE_IMAGE) {
948                                         SpaceImage *sima = (SpaceImage *) sl;
949
950                                         colormanage_check_view_settings(&sima->view_settings, "image editor", default_view);
951                                 }
952                                 else if (sl->spacetype == SPACE_NODE) {
953                                         SpaceNode *snode = (SpaceNode *) sl;
954
955                                         colormanage_check_view_settings(&snode->view_settings, "node editor", default_view);
956                                 }
957                                 else if (sl->spacetype == SPACE_CLIP) {
958                                         SpaceClip *sclip = (SpaceClip *) sl;
959
960                                         colormanage_check_view_settings(&sclip->view_settings, "clip editor", default_view);
961                                 }
962                         }
963                 }
964         }
965 #else
966         (void) bmain;
967 #endif
968 }
969
970 const ColorManagedViewSettings *IMB_view_settings_get_effective(wmWindow *win,
971                 const ColorManagedViewSettings *view_settings)
972 {
973         if (view_settings->flag & COLORMANAGE_VIEW_USE_GLOBAL) {
974                 return &win->view_settings;
975         }
976
977         return view_settings;
978 }
979
980 /*********************** Display functions *************************/
981
982 #ifdef WITH_OCIO
983 ColorManagedDisplay *colormanage_display_get_default(void)
984 {
985         ConstConfigRcPtr *config = OCIO_getCurrentConfig();
986         const char *display;
987
988         if (!config) {
989                 /* no valid OCIO configuration, can't get default display */
990
991                 return NULL;
992         }
993
994         display = OCIO_configGetDefaultDisplay(config);
995
996         OCIO_configRelease(config);
997
998         if (display[0] == '\0')
999                 return NULL;
1000
1001         return colormanage_display_get_named(display);
1002 }
1003 #endif
1004
1005 ColorManagedDisplay *colormanage_display_add(const char *name)
1006 {
1007         ColorManagedDisplay *display;
1008         int index = 0;
1009
1010         if (global_displays.last) {
1011                 ColorManagedDisplay *last_display = global_displays.last;
1012
1013                 index = last_display->index;
1014         }
1015
1016         display = MEM_callocN(sizeof(ColorManagedDisplay), "ColorManagedDisplay");
1017
1018         display->index = index + 1;
1019
1020         BLI_strncpy(display->name, name, sizeof(display->name));
1021
1022         BLI_addtail(&global_displays, display);
1023
1024         return display;
1025 }
1026
1027 ColorManagedDisplay *colormanage_display_get_named(const char *name)
1028 {
1029         ColorManagedDisplay *display;
1030
1031         for (display = global_displays.first; display; display = display->next) {
1032                 if (!strcmp(display->name, name))
1033                         return display;
1034         }
1035
1036         return NULL;
1037 }
1038
1039 ColorManagedDisplay *colormanage_display_get_indexed(int index)
1040 {
1041         /* display indices are 1-based */
1042         return BLI_findlink(&global_displays, index - 1);
1043 }
1044
1045 int IMB_colormanagement_display_get_named_index(const char *name)
1046 {
1047         ColorManagedDisplay *display;
1048
1049         display = colormanage_display_get_named(name);
1050
1051         if (display) {
1052                 return display->index;
1053         }
1054
1055         return 0;
1056 }
1057
1058 const char *IMB_colormanagement_display_get_indexed_name(int index)
1059 {
1060         ColorManagedDisplay *display;
1061
1062         display = colormanage_display_get_indexed(index);
1063
1064         if (display) {
1065                 return display->name;
1066         }
1067
1068         return NULL;
1069 }
1070
1071 /*********************** View functions *************************/
1072
1073 #ifdef WITH_OCIO
1074 ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display)
1075 {
1076         ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1077         const char *name;
1078
1079         if (!config) {
1080                 /* no valid OCIO configuration, can't get default view */
1081
1082                 return NULL;
1083         }
1084
1085         name = OCIO_configGetDefaultView(config, display->name);
1086
1087         OCIO_configRelease(config);
1088
1089         if (name[0] == '\0')
1090                 return NULL;
1091
1092         return colormanage_view_get_named(name);
1093 }
1094 #endif
1095
1096 ColorManagedView *colormanage_view_add(const char *name)
1097 {
1098         ColorManagedView *view;
1099         int index = global_tot_view;
1100
1101         view = MEM_callocN(sizeof(ColorManagedView), "ColorManagedView");
1102         view->index = index + 1;
1103         BLI_strncpy(view->name, name, sizeof(view->name));
1104
1105         BLI_addtail(&global_views, view);
1106
1107         global_tot_view++;
1108
1109         return view;
1110 }
1111
1112 ColorManagedView *colormanage_view_get_named(const char *name)
1113 {
1114         ColorManagedView *view;
1115
1116         for (view = global_views.first; view; view = view->next) {
1117                 if (!strcmp(view->name, name))
1118                         return view;
1119         }
1120
1121         return NULL;
1122 }
1123
1124 ColorManagedView *colormanage_view_get_indexed(int index)
1125 {
1126         /* view transform indices are 1-based */
1127         return BLI_findlink(&global_views, index - 1);
1128 }
1129
1130 int IMB_colormanagement_view_get_named_index(const char *name)
1131 {
1132         ColorManagedView *view = colormanage_view_get_named(name);
1133
1134         if (view) {
1135                 return view->index;
1136         }
1137
1138         return 0;
1139 }
1140
1141 const char *IMB_colormanagement_view_get_indexed_name(int index)
1142 {
1143         ColorManagedView *view = colormanage_view_get_indexed(index);
1144
1145         if (view) {
1146                 return view->name;
1147         }
1148
1149         return "NONE";
1150 }
1151
1152 /*********************** RNA helper functions *************************/
1153
1154 void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
1155 {
1156         ColorManagedDisplay *display;
1157
1158         for (display = global_displays.first; display; display = display->next) {
1159                 EnumPropertyItem item;
1160
1161                 item.value = display->index;
1162                 item.name = display->name;
1163                 item.identifier = display->name;
1164                 item.icon = 0;
1165                 item.description = "";
1166
1167                 RNA_enum_item_add(items, totitem, &item);
1168         }
1169 }
1170
1171 static void colormanagement_view_item_add(EnumPropertyItem **items, int *totitem, ColorManagedView *view)
1172 {
1173         EnumPropertyItem item;
1174
1175         item.value = view->index;
1176         item.name = view->name;
1177         item.identifier = view->name;
1178         item.icon = 0;
1179         item.description = "";
1180
1181         RNA_enum_item_add(items, totitem, &item);
1182 }
1183
1184 void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, const char *display_name)
1185 {
1186         ColorManagedDisplay *display = colormanage_display_get_named(display_name);
1187         ColorManagedView *view;
1188
1189         /* OCIO_TODO: try to get rid of such a hackish stuff */
1190         view = colormanage_view_get_named("ACES ODT Tonecurve");
1191         if (view) {
1192                 colormanagement_view_item_add(items, totitem, view);
1193         }
1194
1195         if (display) {
1196                 LinkData *display_view;
1197
1198                 for (display_view = display->views.first; display_view; display_view = display_view->next) {
1199                         view = display_view->data;
1200
1201                         colormanagement_view_item_add(items, totitem, view);
1202                 }
1203         }
1204 }
1205
1206 /*********************** Partial display buffer update  *************************/
1207
1208 /*
1209  * Partial display update is supposed to be used by such areas as compositor,
1210  * which re-calculates parts of the images and requires updating only
1211  * specified areas of buffers to provide better visual feedback.
1212  *
1213  * To achieve this special context is being constructed. This context is
1214  * holding all buffers which were color managed and transformations which
1215  * need to be applied on this buffers to make them valid.
1216  *
1217  * Updating happens for all buffers from this context using given linear
1218  * float buffer and rectangle area which shall be updated.
1219  *
1220  * Updating every rectangle is thread-save operation due to buffers are
1221  * referenced by the context, so they shouldn't have been deleted
1222  * during execution.
1223  */
1224
1225 typedef struct PartialBufferUpdateItem {
1226         struct PartialBufferUpdateItem *next, *prev;
1227
1228         unsigned char *display_buffer;
1229         void *cache_handle;
1230
1231         int display, view;
1232
1233 #ifdef WITH_OCIO
1234         ConstProcessorRcPtr *processor;
1235 #endif
1236
1237         imb_tonecurveCb tonecurve_func;
1238 } PartialBufferUpdateItem;
1239
1240 typedef struct PartialBufferUpdateContext {
1241         int buffer_width;
1242         int dither, predivide;
1243
1244         ListBase items;
1245 } PartialBufferUpdateContext;
1246
1247 PartialBufferUpdateContext *IMB_partial_buffer_update_context_new(ImBuf *ibuf)
1248 {
1249         PartialBufferUpdateContext *context = NULL;
1250
1251 #ifdef WITH_OCIO
1252         int display;
1253
1254         context = MEM_callocN(sizeof(PartialBufferUpdateContext), "partial buffer update context");
1255
1256         context->buffer_width = ibuf->x;
1257
1258         context->predivide = ibuf->flags & IB_cm_predivide;
1259         context->dither = ibuf->dither;
1260
1261         if (!ibuf->display_buffer_flags) {
1262                 /* there's no cached display buffers, so no need to iterate though bit fields */
1263                 return context;
1264         }
1265
1266         for (display = 0; display < global_tot_display; display++) {
1267                 int display_index = display + 1; /* displays in configuration are 1-based */
1268                 const char *display_name = IMB_colormanagement_display_get_indexed_name(display_index);
1269                 int view_flags = ibuf->display_buffer_flags[display];
1270                 int view = 0;
1271
1272                 while (view_flags != 0) {
1273                         if (view_flags % 2 == 1) {
1274                                 unsigned char *display_buffer;
1275                                 void *cache_handle;
1276                                 int view_index = view + 1; /* views in configuration are 1-based */
1277
1278                                 display_buffer = colormanage_cache_get_validated(ibuf, view_index, display_index, &cache_handle);
1279
1280                                 if (display_buffer) {
1281                                         PartialBufferUpdateItem *item;
1282                                         const char *view_name = IMB_colormanagement_view_get_indexed_name(view_index);
1283                                         float exposure, gamma;
1284
1285                                         colormanage_cache_get_cache_data(cache_handle, &exposure, &gamma);
1286
1287                                         item = MEM_callocN(sizeof(PartialBufferUpdateItem), "partial buffer update item");
1288
1289                                         item->display_buffer = display_buffer;
1290                                         item->cache_handle = cache_handle;
1291                                         item->display = display_index;
1292                                         item->view = view_index;
1293
1294                                         if (!strcmp(view_name, "ACES ODT Tonecurve")) {
1295                                                 item->tonecurve_func = IMB_ratio_preserving_odt_tonecurve;
1296                                         }
1297                                         else {
1298                                                 ConstProcessorRcPtr *processor;
1299
1300                                                 processor = create_display_buffer_processor(view_name, display_name, exposure, gamma);
1301
1302                                                 item->processor = processor;
1303                                         }
1304
1305                                         BLI_addtail(&context->items, item);
1306                                 }
1307                         }
1308
1309                         view_flags /= 2;
1310                         view++;
1311                 }
1312         }
1313 #else
1314         (void) ibuf;
1315 #endif
1316
1317         return context;
1318 }
1319
1320 void IMB_partial_buffer_update_rect(PartialBufferUpdateContext *context, const float *linear_buffer, struct rcti *rect)
1321 {
1322 #ifdef WITH_OCIO
1323         PartialBufferUpdateItem *item;
1324
1325         for (item = context->items.first; item; item = item->next) {
1326                 if (item->processor || item->tonecurve_func) {
1327                         unsigned char *display_buffer = item->display_buffer;
1328                         int x, y;
1329
1330                         for (y = rect->ymin; y < rect->ymax; y++) {
1331                                 for (x = rect->xmin; x < rect->xmax; x++) {
1332                                         int index = (y * context->buffer_width + x) * 4;
1333                                         float pixel[4];
1334
1335                                         if (item->processor) {
1336                                                 copy_v4_v4(pixel, (float *)linear_buffer + index);
1337
1338                                                 OCIO_processorApplyRGBA(item->processor, pixel);
1339
1340                                                 rgba_float_to_uchar(display_buffer + index, pixel);
1341                                         }
1342                                         else {
1343                                                 IMB_buffer_byte_from_float_tonecurve(display_buffer + index, linear_buffer + index,
1344                                                                                      4, context->dither, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
1345                                                                                      context->predivide, 1, 1, 1, 1, item->tonecurve_func);
1346                                         }
1347                                 }
1348                         }
1349                 }
1350         }
1351 #else
1352         (void) context;
1353         (void) linear_buffer;
1354         (void) rect;
1355 #endif
1356 }
1357
1358 void IMB_partial_buffer_update_free(PartialBufferUpdateContext *context, ImBuf *ibuf)
1359 {
1360 #ifdef WITH_OCIO
1361         PartialBufferUpdateItem *item;
1362
1363         IMB_display_buffer_invalidate(ibuf);
1364
1365         item = context->items.first;
1366         while (item) {
1367                 PartialBufferUpdateItem *item_next = item->next;
1368
1369                 /* displays are 1-based, need to go to 0-based arrays indices */
1370                 ibuf->display_buffer_flags[item->display - 1] |= (1 << (item->view - 1));
1371
1372                 colormanage_cache_handle_release(item->cache_handle);
1373
1374                 OCIO_processorRelease(item->processor);
1375
1376                 MEM_freeN(item);
1377
1378                 item = item_next;
1379         }
1380
1381         MEM_freeN(context);
1382 #else
1383         (void) context;
1384         (void) ibuf;
1385 #endif
1386 }