Color Management: finish pipeline changes
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 10 Sep 2012 11:46:15 +0000 (11:46 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 10 Sep 2012 11:46:15 +0000 (11:46 +0000)
This commit hopefully finishes color management pipeline changes, implements
some missed functionality and fixes some bugs.

Mainly changes are related on getting rid of old Color Management flag which
became counter-intuitive in conjunction with OpenColorIO.

Now color management is always assuming to be enabled and non-color managed
pipeline is emulated using display device called None. This display has got
single view which is basically NO-OP (raw) transformation, not applying any
tone curve and displays colors AS-IS. In most cases it behaves the same as
disabling Color Management in shading panel, but there is at least one known
difference in behavior: compositor and sequence editors would output images
in linear space, not in sRGB as it used to be before.

It'll be quite tricky to make this behave in exactly the same way as it
used to, and not sure if we really need to do it.

3D viewport is supposed to be working in sRGB space, no tonemaps would be
applied there. This is another case where compatibility breaks in comparison
with old color management pipeline, but supporting display transformation
would be tricky since it'll also be needed to make GLSL shaders, textures
and so be aware of display transform.

Interface is now aware of display transformation, but it only uses default
display view, no exposure, gamma or curve mapping is supported there.
This is so color widgets could apply display transformation in both
directions. Such behavior is a bit counter-intuitive, but it's currently
the only way to make color picking working smoothly. In theory we'll need
to support color picking color space, but it'll be also a bit tricky since
in Blender display transform is configurable from the interface and could
be used for artistics needs and in such design it's not possible to figure
out invertable color space which could be used for color picking.

In other software it's not so big issue since all color spaces, display
transform and so are strictly defined by pipeline and in this case it is
possible to define color picking space which would be close enough to
display space.

Sequencer's color space now could be configured from the interface --
it's settings are situated in Scene buttons, Color Management panel.
Default space is sRGB. It was made configurable because we used vd16
color space during Mango which was close to Film view used by grading
department.

Sequencer will convert float buffers to this color space before operating
with them hopefully giving better results. Byte buffers wouldn't be
converted to this color space an they'll be handled in their own colors[ace.
Converting them to sequencer's working space would lead to precision loss
without much visible benefits. It shouldn't be an issue since float and
byte images would never be blended together -- byte image would be converted
to float first if it's needed to be blended with float image.

Byte buffers now allowed to be color managed. This was needed to make code
in such areas as baking and rendering don't have hardcoded linear to sRGB
conversions, making things more clear from code point of view.

Input color space is now assigning on image/movie clip load and default
roles are used for this. So for float images default space would be rec709
and for byte images default space would be sRGB.

Added Non-Color color space which is aimed to be used for such things as
normal/heights maps. It's currently the same as raw colorspace, just has
got more clear naming for users. Probably we'll also need to make it not
affected by display transformation.

Think this is all main pipeline-related changes, more details would be there:

http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management

Other changes and fixes:

- Lots of internal code clean up in color management module.

- Made OpenColorIO module using guarded memory allocation. This allowed to
  fix couple of memory leaks and would help preventing leaks in the future.

- Made sure color unpremultiply and dither are supported by all OpenColorIO
  defined color transformations.

- Made compositor's preview images be aware of display transformation.
  Legacy compositor still uses old Color Management flags, but likely we'll
  disable compositor for the release and remove legacy code soon, so don't
  think we'll need to spend time on porting that code to new color management
  system.

- Made OpenGL rendering be aware of display transform when saving render
  result. Now it behaves in the same way as regular rendering.

TODO:

- HSV widgets are using linear rgb/sRGB conversions for single channel,
  not sure how this should be ported to new color pipeline.

- Image stamp would use hardcoded linear rgb to sRGB conversion for
  filling rectangles. Probably it should use default display view
  for this instead, would check this with Brecht.

- Get rid of None color space which was only used for compatibility reasons.

- Made it more clear which color spaces could be used as input space.

- There're also some remained TODO's in the code marked as OCIO_TODO,
  but wouldn't consider them as stoppers for at least this commit.

99 files changed:
intern/opencolorio/CMakeLists.txt
intern/opencolorio/SConscript
intern/opencolorio/ocio_capi.cpp
intern/opencolorio/ocio_capi.h
release/datafiles/colormanagement/config.ocio
release/scripts/startup/bl_ui/properties_render.py
release/scripts/startup/bl_ui/properties_scene.py
source/blender/blenkernel/BKE_colortools.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_scene.h
source/blender/blenkernel/BKE_sequencer.h
source/blender/blenkernel/intern/colortools.c
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/seqeffects.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenloader/intern/readfile.c
source/blender/compositor/COM_compositor.h
source/blender/compositor/intern/COM_CompositorContext.cpp
source/blender/compositor/intern/COM_CompositorContext.h
source/blender/compositor/intern/COM_ExecutionSystem.cpp
source/blender/compositor/intern/COM_ExecutionSystem.h
source/blender/compositor/intern/COM_Node.cpp
source/blender/compositor/intern/COM_Node.h
source/blender/compositor/intern/COM_compositor.cpp
source/blender/compositor/nodes/COM_BlurNode.cpp
source/blender/compositor/nodes/COM_BokehImageNode.cpp
source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
source/blender/compositor/nodes/COM_ColorMatteNode.cpp
source/blender/compositor/nodes/COM_CompositorNode.cpp
source/blender/compositor/nodes/COM_DespeckleNode.cpp
source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
source/blender/compositor/nodes/COM_DilateErodeNode.cpp
source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
source/blender/compositor/nodes/COM_FilterNode.cpp
source/blender/compositor/nodes/COM_ImageNode.cpp
source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
source/blender/compositor/nodes/COM_MixNode.cpp
source/blender/compositor/nodes/COM_MovieClipNode.cpp
source/blender/compositor/nodes/COM_OutputFileNode.cpp
source/blender/compositor/nodes/COM_RenderLayersNode.cpp
source/blender/compositor/nodes/COM_RenderLayersNode.h
source/blender/compositor/nodes/COM_SplitViewerNode.cpp
source/blender/compositor/nodes/COM_TextureNode.cpp
source/blender/compositor/nodes/COM_ViewerNode.cpp
source/blender/compositor/operations/COM_OutputFileOperation.cpp
source/blender/compositor/operations/COM_OutputFileOperation.h
source/blender/compositor/operations/COM_PreviewOperation.cpp
source/blender/compositor/operations/COM_PreviewOperation.h
source/blender/compositor/operations/COM_SplitViewerOperation.cpp
source/blender/compositor/operations/COM_ViewerBaseOperation.cpp
source/blender/compositor/operations/COM_ViewerBaseOperation.h
source/blender/compositor/operations/COM_ViewerOperation.cpp
source/blender/editors/include/ED_view3d.h
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_ops.c
source/blender/editors/interface/interface_regions.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/object/object_bake.c
source/blender/editors/render/render_internal.c
source/blender/editors/render/render_opengl.c
source/blender/editors/render/render_preview.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/space_image/image_buttons.c
source/blender/editors/space_image/image_draw.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_sequencer/sequencer_view.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_material.c
source/blender/imbuf/IMB_colormanagement.h
source/blender/imbuf/IMB_imbuf_types.h
source/blender/imbuf/intern/IMB_colormanagement_intern.h
source/blender/imbuf/intern/allocimbuf.c
source/blender/imbuf/intern/colormanagement.c
source/blender/makesdna/DNA_color_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_image_api.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_space.c
source/blender/nodes/composite/node_composite_tree.c
source/blender/nodes/composite/node_composite_util.c
source/blender/nodes/composite/nodes/node_composite_image.c
source/blender/nodes/composite/nodes/node_composite_outputFile.c
source/blender/render/intern/include/render_result.h
source/blender/render/intern/source/envmap.c
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/render_result.c
source/blender/render/intern/source/render_texture.c
source/blender/render/intern/source/rendercore.c
source/blender/render/intern/source/shadeinput.c
source/blender/windowmanager/intern/wm_files.c

index 3ad2e91..131a829 100644 (file)
@@ -29,7 +29,7 @@ set(INC
 )
 
 set(INC_SYS
-
+       ../guardedalloc
 )
 
 set(SRC
index ef814ed..4860d94 100644 (file)
@@ -4,7 +4,7 @@ Import('env')
 
 sources = env.Glob('*.cpp')
 
-incs = '.'
+incs = '. ../guardedalloc'
 incs += ' ' + env['BF_OCIO_INC']
 
 if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
index 6fec118..6fb719d 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <OpenColorIO/OpenColorIO.h>
 
+#include "MEM_guardedalloc.h"
 
 #define OCIO_CAPI_IMPLEMENTATION
 #include "ocio_capi.h"
 #  define OCIO_abort() abort()
 #endif
 
+#if defined(_MSC_VER)
+#  define __func__ __FUNCTION__
+#endif
+
+#define MEM_NEW(type) new(MEM_mallocN(sizeof(type), __func__)) type()
+#define MEM_DELETE(what, type) { what->~type(); MEM_freeN(what); } (void)0
+
 static void OCIO_reportError(const char *err)
 {
        std::cerr << "OpenColorIO Error: " << err << std::endl;
@@ -53,7 +61,8 @@ static void OCIO_reportException(Exception &exception)
 
 ConstConfigRcPtr *OCIO_getCurrentConfig(void)
 {
-       ConstConfigRcPtr *config =  new ConstConfigRcPtr();
+       ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
+
        try {
                *config = GetCurrentConfig();
 
@@ -79,7 +88,7 @@ void OCIO_setCurrentConfig(const ConstConfigRcPtr *config)
 
 ConstConfigRcPtr *OCIO_configCreateFromEnv(void)
 {
-       ConstConfigRcPtr *config =  new ConstConfigRcPtr();
+       ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
 
        try {
                *config = Config::CreateFromEnv();
@@ -97,7 +106,7 @@ ConstConfigRcPtr *OCIO_configCreateFromEnv(void)
 
 ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename)
 {
-       ConstConfigRcPtr *config =  new ConstConfigRcPtr();
+       ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
 
        try {
                *config = Config::CreateFromFile(filename);
@@ -114,7 +123,7 @@ ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename)
 
 void OCIO_configRelease(ConstConfigRcPtr *config)
 {
-       delete config;
+       MEM_DELETE(config, ConstConfigRcPtr);
 }
 
 int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config)
@@ -143,7 +152,7 @@ const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int in
 
 ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name)
 {
-       ConstColorSpaceRcPtr *cs =  new ConstColorSpaceRcPtr();
+       ConstColorSpaceRcPtr *cs = MEM_NEW(ConstColorSpaceRcPtr);
 
        try {
                *cs = (*config)->getColorSpace(name);
@@ -153,7 +162,7 @@ ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const c
        }
        catch (Exception &exception) {
                OCIO_reportException(exception);
-               delete cs;
+               MEM_DELETE(cs, ConstColorSpaceRcPtr);
        }
 
        return NULL;
@@ -257,12 +266,12 @@ const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const
 
 void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs)
 {
-       delete cs;
+       MEM_DELETE(cs, ConstColorSpaceRcPtr);
 }
 
 ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName)
 {
-       ConstProcessorRcPtr *p =  new ConstProcessorRcPtr();
+       ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr);
 
        try {
                *p = (*config)->getProcessor(srcName, dstName);
@@ -279,7 +288,7 @@ ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config,
 
 ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform)
 {
-       ConstProcessorRcPtr *p =  new ConstProcessorRcPtr();
+       ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr);
 
        try {
                *p = (*config)->getProcessor(*transform);
@@ -367,7 +376,8 @@ void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pi
 
 void OCIO_processorRelease(ConstProcessorRcPtr *p)
 {
-       delete p;
+       p->~ConstProcessorRcPtr();
+       MEM_freeN(p);
 }
 
 const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs)
@@ -387,7 +397,7 @@ const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs)
 
 DisplayTransformRcPtr *OCIO_createDisplayTransform(void)
 {
-       DisplayTransformRcPtr *dt =  new DisplayTransformRcPtr();
+       DisplayTransformRcPtr *dt = MEM_NEW(DisplayTransformRcPtr);
 
        *dt = DisplayTransform::Create();
 
@@ -421,15 +431,15 @@ void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformR
 
 void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt)
 {
-       delete dt;
-       dt = NULL;
+       MEM_DELETE(dt, DisplayTransformRcPtr);
 }
 
 PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels,
-                                                                                       long chanStrideBytes, long xStrideBytes, long yStrideBytes)
+                                            long chanStrideBytes, long xStrideBytes, long yStrideBytes)
 {
        try {
-               PackedImageDesc *id = new PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
+               void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__);
+               PackedImageDesc *id = new(mem) PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
 
                return id;
        }
@@ -442,13 +452,12 @@ PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height
 
 void OCIO_packedImageDescRelease(PackedImageDesc* id)
 {
-       delete id;
-       id = NULL;
+       MEM_DELETE(id, PackedImageDesc);
 }
 
 ExponentTransformRcPtr *OCIO_createExponentTransform(void)
 {
-       ExponentTransformRcPtr *et =  new ExponentTransformRcPtr();
+       ExponentTransformRcPtr *et = MEM_NEW(ExponentTransformRcPtr);
 
        *et = ExponentTransform::Create();
 
@@ -462,12 +471,12 @@ void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exp
 
 void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et)
 {
-       delete et;
+       MEM_DELETE(et, ExponentTransformRcPtr);
 }
 
 MatrixTransformRcPtr *OCIO_createMatrixTransform(void)
 {
-       MatrixTransformRcPtr *mt = new MatrixTransformRcPtr();
+       MatrixTransformRcPtr *mt = MEM_NEW(MatrixTransformRcPtr);
 
        *mt = MatrixTransform::Create();
 
@@ -481,7 +490,7 @@ void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, co
 
 void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt)
 {
-       delete mt;
+       MEM_DELETE(mt, MatrixTransformRcPtr);
 }
 
 void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4f)
index c3830f3..11973bc 100644 (file)
@@ -39,10 +39,12 @@ extern "C" {
 
 
 #ifndef OCIO_CAPI_IMPLEMENTATION
-       #define OCIO_ROLE_SCENE_LINEAR  "scene_linear"
-       #define OCIO_ROLE_COLOR_PICKING "color_picking"
-       #define OCIO_ROLE_TEXTURE_PAINT "texture_paint"
-       #define OCIO_ROLE_SEQUENCER     "sequencer"
+       #define OCIO_ROLE_SCENE_LINEAR       "scene_linear"
+       #define OCIO_ROLE_COLOR_PICKING      "color_picking"
+       #define OCIO_ROLE_TEXTURE_PAINT      "texture_paint"
+       #define OCIO_ROLE_DEFAULT_BYTE       "default_byte"
+       #define OCIO_ROLE_DEFAULT_FLOAT      "default_float"
+       #define OCIO_ROLE_DEFAULT_SEQUENCER  "default_sequencer"
 
        OCIO_DECLARE_HANDLE(ConstConfigRcPtr);
        OCIO_DECLARE_HANDLE(ConstColorSpaceRcPtr);
index 674c2ad..e8fb03b 100644 (file)
@@ -1,3 +1,7 @@
+# OpenCOlorIO configuration file for Blender
+#
+# Based on aces, nuke-default and spi configurations from OpenColorIO-Config
+
 ocio_profile_version: 1
 
 search_path: luts
@@ -7,11 +11,23 @@ luma: [0.2126, 0.7152, 0.0722]
 description: RRT version ut33
 
 roles:
-  color_picking: raw
   reference: aces
+
+  # Internal scene linear space
   scene_linear: rec709
+
+  # Default color space for byte image
+  default_byte: sRGB
+
+  # Default color space for float images
+  default_float: rec709
+
+  # Default color space sequencer is working in
+  default_sequencer: sRGB
+
+  # Color spaces for color picking and exture painting (not internally supported yet)
+  color_picking: raw
   texture_paint: raw
-  sequencer: vd16
 
 displays:
   sRGB:
@@ -33,8 +49,10 @@ displays:
     - !<View> {name: DCI, colorspace: dci_xyz}
     - !<View> {name: Raw, colorspace: raw}
     - !<View> {name: Log, colorspace: adx10}
+  None:
+    - !<View> {name: Default, colorspace: raw}
 
-active_displays: [sRGB, P3DCI, Rec709, XYZ]
+active_displays: [sRGB, P3DCI, Rec709, XYZ, None]
 active_views: [Default, RRT, Raw, Log]
 
 colorspaces:
@@ -238,3 +256,14 @@ colorspaces:
       children:
         - !<FileTransform> {src: vd16.spi1d, interpolation: nearest}
         - !<FileTransform> {src: rec709_to_aces.spimtx, interpolation: linear}
+
+  - !<ColorSpace>
+    name: Non-Color
+    family: raw
+    description: |
+        Color space used for images which contains non-color data (i,e, normal maps)
+    equalitygroup:
+    bitdepth: 32f
+    isdata: true
+    allocation: uniform
+    allocationvars: [0, 1]
index 8b632ef..b777fcd 100644 (file)
@@ -316,10 +316,7 @@ class RENDER_PT_shading(RenderButtonsPanel, Panel):
 
         col = split.column()
         col.prop(rd, "use_raytrace", text="Ray Tracing")
-        col.prop(rd, "use_color_management")
-        sub = col.row()
-        sub.active = rd.use_color_management == True
-        sub.prop(rd, "use_color_unpremultiply")
+        col.prop(rd, "use_color_unpremultiply")
         col.prop(rd, "alpha_mode", text="Alpha")
 
 
index fcfd29c..2ccdb9c 100644 (file)
@@ -242,8 +242,19 @@ class SCENE_PT_color_management(Panel):
 
         scene = context.scene
 
-        layout.prop(scene.display_settings, "display_device")
-        layout.template_colormanaged_view_settings(scene, "view_settings")
+        col = layout.column()
+        col.label(text="Display:")
+        col.prop(scene.display_settings, "display_device")
+
+        col = layout.column()
+        col.separator()
+        col.label(text="Render:")
+        col.template_colormanaged_view_settings(scene, "view_settings")
+
+        col = layout.column()
+        col.separator()
+        col.label(text="Sequencer:")
+        col.prop(scene.sequencer_colorspace_settings, "name")
 
 
 class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
index 7c2c9bb..d19c57b 100644 (file)
@@ -92,8 +92,11 @@ void                curvemapping_do_ibuf(struct CurveMapping *cumap, struct ImBu
 void                curvemapping_premultiply(struct CurveMapping *cumap, int restore);
 
 
-void                BKE_histogram_update_sample_line(struct Histogram *hist, struct ImBuf *ibuf, const short use_color_management);
-void                scopes_update(struct Scopes *scopes, struct ImBuf *ibuf, int use_color_management);
+void                BKE_histogram_update_sample_line(struct Histogram *hist, struct ImBuf *ibuf,
+                                                     const struct ColorManagedViewSettings *view_settings,
+                                                     const struct ColorManagedDisplaySettings *display_settings);
+void                scopes_update(struct Scopes *scopes, struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings,
+                                  const struct ColorManagedDisplaySettings *display_settings);
 void                scopes_free(struct Scopes *scopes);
 void                scopes_new(struct Scopes *scopes);
 
index 438d511..6ad2ad9 100644 (file)
@@ -64,6 +64,8 @@ struct Tex;
 struct SpaceNode;
 struct ARegion;
 struct Object;
+struct ColorManagedViewSettings;
+struct ColorManagedDisplaySettings;
 
 /* ************** NODE TYPE DEFINITIONS ***** */
 
@@ -725,7 +727,8 @@ void            ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
 struct CompBuf;
 struct bNodeTreeExec *ntreeCompositBeginExecTree(struct bNodeTree *ntree, int use_tree_data);
 void ntreeCompositEndExecTree(struct bNodeTreeExec *exec, int use_tree_data);
-void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews);
+void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews,
+                           const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings);
 void ntreeCompositTagRender(struct Scene *sce);
 int ntreeCompositTagAnimated(struct bNodeTree *ntree);
 void ntreeCompositTagGenerators(struct bNodeTree *ntree);
index bce4243..023b7e8 100644 (file)
@@ -108,6 +108,8 @@ float get_render_aosss_error(struct RenderData *r, float error);
 
 int BKE_scene_use_new_shading_nodes(struct Scene *scene);
 
+void BKE_scene_disable_color_management(struct Scene *scene);
+
 #ifdef __cplusplus
 }
 #endif
index 5bef0b2..81fb936 100644 (file)
@@ -176,6 +176,16 @@ struct ImBuf *BKE_sequencer_give_ibuf_direct(SeqRenderData context, float cfra,
 struct ImBuf *BKE_sequencer_give_ibuf_seqbase(SeqRenderData context, float cfra, int chan_shown, struct ListBase *seqbasep);
 void BKE_sequencer_give_ibuf_prefetch_request(SeqRenderData context, float cfra, int chan_shown);
 
+/* **********************************************************************
+ * sequencer.c
+ *
+ * sequencer color space functions
+ * ********************************************************************** */
+
+void BKE_sequencer_imbuf_to_sequencer_space(struct Scene *scene, struct ImBuf *ibuf, int make_float);
+void BKE_sequencer_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf);
+void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]);
+
 /* **********************************************************************
  * sequencer scene functions
  * ********************************************************************** */
@@ -349,7 +359,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
 struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
 
 /* view3d draw callback, run when not in background view */
-typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, int, char[256]);
+typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, int, int, char[256]);
 extern SequencerDrawView sequencer_view3d_cb;
 
 /* copy/paste */
index 65bffe4..27651ac 100644 (file)
@@ -998,7 +998,8 @@ static void save_sample_line(Scopes *scopes, const int idx, const float fx, cons
        }
 }
 
-void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const short use_color_management)
+void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
+                                      const ColorManagedDisplaySettings *display_settings)
 {
        int i, x, y;
        float *fp;
@@ -1010,6 +1011,8 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const short
        int y1 = 0.5f + hist->co[0][1] * ibuf->y;
        int y2 = 0.5f + hist->co[1][1] * ibuf->y;
 
+       struct ColormanageProcessor *cm_processor = NULL;
+
        hist->channels = 3;
        hist->x_resolution = 256;
        hist->xmax = 1.0f;
@@ -1017,6 +1020,9 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const short
 
        if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
 
+       if (ibuf->rect_float)
+               cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+
        /* persistent draw */
        hist->flag |= HISTO_FLAG_SAMPLELINE; /* keep drawing the flag after */
 
@@ -1031,10 +1037,8 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const short
                        if (ibuf->rect_float) {
                                fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
 
-                               if (use_color_management)
-                                       linearrgb_to_srgb_v3_v3(rgb, fp);
-                               else
-                                       copy_v3_v3(rgb, fp);
+                               copy_v3_v3(rgb, fp);
+                               IMB_colormanagement_processor_apply_v3(cm_processor, rgb);
 
                                hist->data_luma[i]  = rgb_to_luma(rgb);
                                hist->data_r[i]     = rgb[0];
@@ -1052,9 +1056,13 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const short
                        }
                }
        }
+
+       if (cm_processor)
+               IMB_colormanagement_processor_free(cm_processor);
 }
 
-void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
+void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
+                   const ColorManagedDisplaySettings *display_settings)
 {
        int x, y, c;
        unsigned int n, nl;
@@ -1067,6 +1075,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
        int ycc_mode = -1;
        const short is_float = (ibuf->rect_float != NULL);
 
+       struct ColormanageProcessor *cm_processor = NULL;
+
        if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
 
        if (scopes->ok == 1) return;
@@ -1136,6 +1146,9 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
        else
                rc = (unsigned char *)ibuf->rect;
 
+       if (ibuf->rect_float)
+               cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+
        for (y = 0; y < ibuf->y; y++) {
                if (savedlines < scopes->sample_lines && y >= ((savedlines) * ibuf->y) / (scopes->sample_lines + 1)) {
                        saveline = 1;
@@ -1146,11 +1159,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
                for (x = 0; x < ibuf->x; x++) {
 
                        if (is_float) {
-                               if (use_color_management)
-                                       linearrgb_to_srgb_v3_v3(rgba, rf);
-                               else
-                                       copy_v3_v3(rgba, rf);
-                               rgba[3] = rf[3];
+                               copy_v4_v4(rgba, rf);
+                               IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
                        }
                        else {
                                for (c = 0; c < 4; c++)
@@ -1221,6 +1231,9 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
        MEM_freeN(bin_b);
        MEM_freeN(bin_a);
 
+       if (cm_processor)
+               IMB_colormanagement_processor_free(cm_processor);
+
        scopes->ok = 1;
 }
 
index a0839a5..3d1133b 100644 (file)
@@ -301,6 +301,12 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
                else
                        ibuf->flags &= ~IB_cm_predivide;
 
+               if (ima->source == IMA_SRC_GENERATED) {
+                       /* for other image types spaces are set by image_initialize_after_load */
+
+                       IMB_colormanagement_imbuf_assign_spaces(ibuf, &ima->colorspace_settings);
+               }
+
                /* this function accepts (link == NULL) */
                BLI_insertlinkbefore(&ima->ibufs, link, ibuf);
 
@@ -1499,7 +1505,9 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec
 
        /* this could be an argument if we want to operate on non linear float imbuf's
         * for now though this is only used for renders which use scene settings */
-       const int do_color_management = (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) != 0;
+
+       /* OCIO_TODO: for now harcode sRGB to linearrgb conversion, need to be fixed ASAP */
+       const int do_color_management = TRUE;
 
 #define BUFF_MARGIN_X 2
 #define BUFF_MARGIN_Y 1
@@ -2586,7 +2594,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        /* invalidate color managed buffers if render result changed */
        BLI_lock_thread(LOCK_COLORMANAGE);
        if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) {
-               IMB_display_buffer_invalidate(ibuf);
+               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
        }
 
        ibuf->x = rres.rectx;
@@ -2626,8 +2634,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
 
        BLI_unlock_thread(LOCK_COLORMANAGE);
 
-       /* since its possible to access the buffer from the image directly, set the profile [#25073] */
-       ibuf->profile = (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) ? IB_PROFILE_LINEAR_RGB : IB_PROFILE_NONE;
+       ibuf->profile = IB_PROFILE_LINEAR_RGB;
        ibuf->dither = dither;
 
        if (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) {
index 1bd8f3d..2dec725 100644 (file)
@@ -77,6 +77,8 @@
 
 #include "RE_engine.h"
 
+#include "IMB_colormanagement.h"
+
 //XXX #include "BIF_previewrender.h"
 //XXX #include "BIF_editseq.h"
 
@@ -384,7 +386,14 @@ Scene *BKE_scene_add(const char *name)
        sce->r.frs_sec_base = 1;
        sce->r.edgeint = 10;
        sce->r.ocres = 128;
+
+       /* OCIO_TODO: for forwards compatibiliy only, so if no tonecurve are used,
+        *            images would look in the same way as in current blender
+        *
+        *            perhaps at some point should be completely deprecated?
+        */
        sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
+
        sce->r.gauss = 1.0;
        
        /* deprecated but keep for upwards compat */
@@ -1255,3 +1264,19 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene)
                base = base->next;
        }
 }
+
+void BKE_scene_disable_color_management(Scene *scene)
+{
+       ColorManagedDisplaySettings *display_settings = &scene->display_settings;
+       ColorManagedViewSettings *view_settings = &scene->view_settings;
+       const char *view;
+
+       /* NOTE: None display with Default view should always exist in OCIO configuration, otherwise it wouldn't work as expected */
+       BLI_strncpy(display_settings->display_device, "None", sizeof(display_settings->display_device));
+
+       view = IMB_colormanagement_view_get_default_name(display_settings->display_device);
+
+       if (view) {
+               BLI_strncpy(view_settings->view_transform, view, sizeof(view_settings->view_transform));
+       }
+}
index acf38ac..eaf3ec3 100644 (file)
@@ -120,13 +120,13 @@ static ImBuf *prepare_effect_imbufs(SeqRenderData context, ImBuf *ibuf1, ImBuf *
        }
        
        if (ibuf1 && !ibuf1->rect_float && out->rect_float) {
-               IMB_colormanagement_imbuf_to_sequencer_space(ibuf1, TRUE);
+               BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf1, TRUE);
        }
        if (ibuf2 && !ibuf2->rect_float && out->rect_float) {
-               IMB_colormanagement_imbuf_to_sequencer_space(ibuf2, TRUE);
+               BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf2, TRUE);
        }
        if (ibuf3 && !ibuf3->rect_float && out->rect_float) {
-               IMB_colormanagement_imbuf_to_sequencer_space(ibuf3, TRUE);
+               BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf3, TRUE);
        }
        
        if (ibuf1 && !ibuf1->rect && !out->rect_float) {
index 611b175..5e79de7 100644 (file)
@@ -309,6 +309,94 @@ void BKE_sequencer_editing_free(Scene *scene)
        scene->ed = NULL;
 }
 
+/*********************** Sequencer color space functions  *************************/
+
+void BKE_sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
+{
+       IMB_colormanagement_imbuf_assign_spaces(ibuf, NULL);
+       IMB_colormanagement_imbuf_assign_float_space(ibuf, &scene->sequencer_colorspace_settings);
+}
+
+void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_float)
+{
+       const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+       const char *to_colorspace = scene->sequencer_colorspace_settings.name;
+       int predivide = ibuf->flags & IB_cm_predivide;
+
+       if (!ibuf->rect_float) {
+               if (make_float && ibuf->rect) {
+                       /* when converting byte buffer to float in sequencer we need to make float
+                        * buffer be in sequencer's working space, which is currently only doable
+                        * from linear space.
+                        *
+                        */
+
+                       /*
+                        * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's
+                        */
+
+                       IMB_colormanagement_imbuf_float_from_rect(ibuf);
+               }
+               else {
+                       /* if there's only byte buffer in image it's already in compositor's working space,
+                        * nothing to do here
+                        */
+
+                       return;
+               }
+       }
+
+       if (from_colorspace && from_colorspace[0] != '\0') {
+               if (ibuf->rect)
+                       imb_freerectImBuf(ibuf);
+
+               IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+                                                      from_colorspace, to_colorspace, predivide);
+
+               ibuf->profile = IB_PROFILE_SRGB;
+       }
+       else {
+               /* if no color management enables fallback to legacy conversion */
+               IMB_convert_profile(ibuf, IB_PROFILE_NONE);
+       }
+}
+
+void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
+{
+       const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+       const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
+       if (!ibuf->rect_float)
+               return;
+
+       if (to_colorspace && to_colorspace[0] != '\0') {
+               int predivide = ibuf->flags & IB_cm_predivide;
+
+               IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+                                                      from_colorspace, to_colorspace, predivide);
+
+               ibuf->profile = IB_PROFILE_LINEAR_RGB;
+       }
+       else {
+               /* if no color management enables fallback to legacy conversion */
+               IMB_convert_profile(ibuf, IB_PROFILE_LINEAR_RGB);
+       }
+}
+
+void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4])
+{
+       const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+       const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
+       if (to_colorspace && to_colorspace[0] != '\0') {
+               IMB_colormanagement_transform_v4(pixel, from_colorspace, to_colorspace);
+       }
+       else {
+               /* if no color management enables fallback to legacy conversion */
+               srgb_to_linearrgb_v4(pixel, pixel);
+       }
+}
+
 /*********************** sequencer pipeline functions *************************/
 
 SeqRenderData BKE_sequencer_new_render_data(Main *bmain, Scene *scene, int rectx, int recty, int preview_render_size)
@@ -1220,7 +1308,12 @@ static ImBuf *seq_proxy_fetch(SeqRenderData context, Sequence *seq, int cfra)
        }
 
        if (BLI_exists(name)) {
-               return IMB_loadiffname(name, IB_rect);
+               ImBuf *ibuf = IMB_loadiffname(name, IB_rect);
+
+               if (ibuf)
+                       BKE_sequencer_imbuf_assign_spaces(context.scene, ibuf);
+
+               return ibuf;
        }
        else {
                return NULL;
@@ -1828,7 +1921,7 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra,
 
        if (seq->flag & SEQ_MAKE_FLOAT) {
                if (!ibuf->rect_float) {
-                       IMB_colormanagement_imbuf_to_sequencer_space(ibuf, TRUE);
+                       BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf, TRUE);
                }
 
                if (ibuf->rect) {
@@ -1895,6 +1988,8 @@ static void copy_to_ibuf_still(SeqRenderData context, Sequence *seq, float nr, I
                 * changing the cached image... */
                ibuf = IMB_dupImBuf(ibuf);
 
+               BKE_sequencer_imbuf_assign_spaces(context.scene, ibuf);
+
                if (nr == 0) {
                        BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL, ibuf);
                } 
@@ -2309,7 +2404,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float
                /* opengl offscreen render */
                BKE_scene_update_for_newframe(context.bmain, scene, scene->lay);
                ibuf = sequencer_view3d_cb(scene, camera, context.rectx, context.recty,
-                                          IB_rect, context.scene->r.seq_prev_type, TRUE, err_out);
+                                          IB_rect, context.scene->r.seq_prev_type, TRUE, FALSE, err_out);
                if (ibuf == NULL) {
                        fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
                }
@@ -2341,7 +2436,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float
 
                        /* float buffers in the sequencer are not linear */
                        ibuf->profile = IB_PROFILE_LINEAR_RGB;
-                       IMB_colormanagement_imbuf_to_sequencer_space(ibuf, FALSE);
+                       BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf, FALSE);
                }
                else if (rres.rect32) {
                        ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
@@ -2448,7 +2543,7 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo
 
                                /* all sequencer color is done in SRGB space, linear gives odd crossfades */
                                if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
-                                       IMB_colormanagement_imbuf_to_sequencer_space(ibuf, FALSE);
+                                       BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf, FALSE);
 
                                copy_to_ibuf_still(context, seq, nr, ibuf);
 
@@ -2496,6 +2591,7 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo
                case SEQ_TYPE_MOVIECLIP:
                {
                        ibuf = seq_render_movieclip_strip(context, seq, nr);
+                       BKE_sequencer_imbuf_assign_spaces(context.scene, ibuf);
 
                        if (ibuf && use_preprocess) {
                                ImBuf *i = IMB_dupImBuf(ibuf);
@@ -2519,6 +2615,9 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo
                }
        }
 
+       if (ibuf)
+               BKE_sequencer_imbuf_assign_spaces(context.scene, ibuf);
+
        return ibuf;
 }
 
index 65d29c1..115c141 100644 (file)
@@ -7923,6 +7923,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                }
        }
 
+       /* color management pipeline changes compatibility code */
+       {
+               Scene *scene;
+
+               for (scene = main->scene.first; scene; scene = scene->id.next) {
+                       if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) {
+                               ColorManagedDisplaySettings *display_settings = &scene->display_settings;
+
+                               if (display_settings->display_device[0] == 0) {
+                                       BKE_scene_disable_color_management(scene);
+                               }
+                       }
+               }
+       }
+
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
 
index f35bf71..a64583b 100644 (file)
@@ -24,6 +24,7 @@
 extern "C" {
  #endif
 
+#include "DNA_color_types.h"
 #include "DNA_node_types.h"
 
 /**
@@ -299,8 +300,20 @@ extern "C" {
  *
  *     - output nodes can have different priorities in the WorkScheduler.
  * This is implemented in the COM_execute function.
+ *
+ * @param viewSettings
+ *   reference to view settings used for color management
+ *
+ * @param displaySettings
+ *   reference to display settings used for color management
+ *
+ * OCIO_TODO: this options only used in rare cases, namely in output file node,
+ *            so probably this settings could be passed in a nicer way.
+ *            should be checked further, probably it'll be also needed for preview
+ *            generation in display space
  */
-void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering);
+void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering,
+                 const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
 
 /**
  * @brief Deinitialize the compositor caches and allocated memory.
index fbdb4cd..e1cc25d 100644 (file)
@@ -31,6 +31,8 @@ CompositorContext::CompositorContext()
        this->m_hasActiveOpenCLDevices = false;
        this->m_activegNode = NULL;
        this->m_fastCalculation = false;
+       this->m_viewSettings = NULL;
+       this->m_displaySettings = NULL;
 }
 
 const int CompositorContext::getFramenumber() const
@@ -42,13 +44,3 @@ const int CompositorContext::getFramenumber() const
                return -1; /* this should never happen */
        }
 }
-
-const int CompositorContext::isColorManaged() const
-{
-       if (this->m_rd) {
-               return this->m_rd->color_mgt_flag & R_COLOR_MANAGEMENT;
-       }
-       else {
-               return 0; /* this should never happen */
-       }
-}
index 2f6abf3..2f5e8c0 100644 (file)
@@ -27,6 +27,7 @@
 #include "BKE_text.h"
 #include <string>
 #include "DNA_node_types.h"
+#include "DNA_color_types.h"
 #include "BLI_rect.h"
 #include "DNA_scene_types.h"
 #include "COM_defines.h"
@@ -79,6 +80,9 @@ private:
         */
        bool m_fastCalculation;
 
+       /* @brief color management settings */
+       const ColorManagedViewSettings *m_viewSettings;
+       const ColorManagedDisplaySettings *m_displaySettings;
 public:
        /**
         * @brief constructor initializes the context with default values.
@@ -125,6 +129,26 @@ public:
         */
        const RenderData *getRenderData() const { return this->m_rd; }
 
+       /**
+        * @brief set view settings of color color management
+        */
+       void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; }
+
+       /**
+        * @brief get view settings of color color management
+        */
+       const ColorManagedViewSettings *getViewSettings() const { return this->m_viewSettings; }
+
+       /**
+        * @brief set display settings of color color management
+        */
+       void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; }
+
+       /**
+        * @brief get display settings of color color management
+        */
+       const ColorManagedDisplaySettings *getDisplaySettings() const { return this->m_displaySettings; }
+
        /**
         * @brief set the quality
         */
@@ -152,8 +176,6 @@ public:
        
        int getChunksize() { return this->getbNodeTree()->chunksize; }
        
-       const int isColorManaged() const;
-       
        void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;}
        bool isFastCalculation() {return this->m_fastCalculation;}
 };
index 801505e..a13717c 100644 (file)
@@ -44,7 +44,8 @@
 #include "MEM_guardedalloc.h"
 #endif
 
-ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation)
+ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation,
+                                 const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
 {
        this->m_context.setbNodeTree(editingtree);
        this->m_context.setFastCalculation(fastcalculation);
@@ -69,6 +70,9 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool re
        ExecutionSystemHelper::addbNodeTree(*this, 0, editingtree, NULL);
 
        this->m_context.setRenderData(rd);
+       this->m_context.setViewSettings(viewSettings);
+       this->m_context.setDisplaySettings(displaySettings);
+
        this->convertToOperations();
        this->groupOperations(); /* group operations in ExecutionGroups */
        unsigned int index;
index 39e7bc8..56a60bf 100644 (file)
@@ -25,6 +25,7 @@ class ExecutionGroup;
 #ifndef _COM_ExecutionSystem_h
 #define _COM_ExecutionSystem_h
 
+#include "DNA_color_types.h"
 #include "DNA_node_types.h"
 #include <vector>
 #include "COM_Node.h"
@@ -156,7 +157,8 @@ public:
         * @param editingtree [bNodeTree *]
         * @param rendering [true false]
         */
-       ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation);
+       ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation,
+                       const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
 
        /**
         * Destructor
index 50393d1..5922b0e 100644 (file)
@@ -75,12 +75,12 @@ void Node::addSetValueOperation(ExecutionSystem *graph, InputSocket *inputsocket
        graph->addOperation(operation);
 }
 
-void Node::addPreviewOperation(ExecutionSystem *system, OutputSocket *outputSocket)
+void Node::addPreviewOperation(ExecutionSystem *system, CompositorContext *context, OutputSocket *outputSocket)
 {
        if (this->isInActiveGroup()) {
                if (!(this->getbNode()->flag & NODE_HIDDEN)) { // do not calculate previews of hidden nodes.
                        if (this->getbNode()->flag & NODE_PREVIEW) {
-                               PreviewOperation *operation = new PreviewOperation();
+                               PreviewOperation *operation = new PreviewOperation(context->getViewSettings(), context->getDisplaySettings());
                                system->addOperation(operation);
                                operation->setbNode(this->getbNode());
                                operation->setbNodeTree(system->getContext().getbNodeTree());
@@ -90,11 +90,11 @@ void Node::addPreviewOperation(ExecutionSystem *system, OutputSocket *outputSock
        }
 }
 
-void Node::addPreviewOperation(ExecutionSystem *system, InputSocket *inputSocket)
+void Node::addPreviewOperation(ExecutionSystem *system, CompositorContext *context, InputSocket *inputSocket)
 {
        if (inputSocket->isConnected() && this->isInActiveGroup()) {
                OutputSocket *outputsocket = inputSocket->getConnection()->getFromSocket();
-               this->addPreviewOperation(system, outputsocket);
+               this->addPreviewOperation(system, context, outputsocket);
        }
 }
 
index 7ce40e3..bfccd06 100644 (file)
@@ -135,8 +135,8 @@ public:
         */
        OutputSocket *findOutputSocketBybNodeSocket(bNodeSocket *socket);
 protected:
-       void addPreviewOperation(ExecutionSystem *system, InputSocket *inputSocket);
-       void addPreviewOperation(ExecutionSystem *system, OutputSocket *outputSocket);
+       void addPreviewOperation(ExecutionSystem *system, CompositorContext *context, InputSocket *inputSocket);
+       void addPreviewOperation(ExecutionSystem *system, CompositorContext *context, OutputSocket *outputSocket);
        
        bNodeSocket *getEditorInputSocket(int editorNodeInputSocketIndex);
        bNodeSocket *getEditorOutputSocket(int editorNodeOutputSocketIndex);
index cb9166c..5cfcd83 100644 (file)
@@ -42,7 +42,9 @@ void intern_freeCompositorCaches()
        deintializeDistortionCache();
 }
 
-void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering)
+void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering,
+                 const ColorManagedViewSettings *viewSettings,
+                 const ColorManagedDisplaySettings *displaySettings)
 {
        /* initialize mutex, TODO this mutex init is actually not thread safe and
         * should be done somewhere as part of blender startup, all the other
@@ -71,7 +73,7 @@ void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering)
        bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering;
        /* initialize execution system */
        if (twopass) {
-               ExecutionSystem *system = new ExecutionSystem(rd, editingtree, rendering, twopass);
+               ExecutionSystem *system = new ExecutionSystem(rd, editingtree, rendering, twopass, viewSettings, displaySettings);
                system->execute();
                delete system;
                
@@ -84,7 +86,7 @@ void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering)
        }
 
        
-       ExecutionSystem *system = new ExecutionSystem(rd, editingtree, rendering, false);
+       ExecutionSystem *system = new ExecutionSystem(rd, editingtree, rendering, false, viewSettings, displaySettings);
        system->execute();
        delete system;
 
index e39ef2b..4f120ea 100644 (file)
@@ -57,7 +57,7 @@ void BlurNode::convertToOperations(ExecutionSystem *graph, CompositorContext *co
                this->getInputSocket(1)->relinkConnections(operationfgb->getInputSocket(1), 1, graph);
                this->getOutputSocket(0)->relinkConnections(operationfgb->getOutputSocket(0));
                graph->addOperation(operationfgb);
-               addPreviewOperation(graph, operationfgb->getOutputSocket());
+               addPreviewOperation(graph, context, operationfgb->getOutputSocket());
        }
        else if (editorNode->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) {
                MathAddOperation *clamp = new MathAddOperation();
@@ -97,7 +97,7 @@ void BlurNode::convertToOperations(ExecutionSystem *graph, CompositorContext *co
                addLink(graph, operationy->getOutputSocket(), operation->getInputSocket(1));
                graph->addOperation(operation);
                this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket());
-               addPreviewOperation(graph, operation->getOutputSocket());
+               addPreviewOperation(graph, context, operation->getOutputSocket());
        }
        else if (!data->bokeh) {
                GaussianXBlurOperation *operationx = new GaussianXBlurOperation();
@@ -115,7 +115,7 @@ void BlurNode::convertToOperations(ExecutionSystem *graph, CompositorContext *co
                graph->addOperation(operationy);
                addLink(graph, operationx->getOutputSocket(), operationy->getInputSocket(0));
                addLink(graph, operationx->getInputSocket(1)->getConnection()->getFromSocket(), operationy->getInputSocket(1));
-               addPreviewOperation(graph, operationy->getOutputSocket());
+               addPreviewOperation(graph, context, operationy->getOutputSocket());
 
                if (!connectedSizeSocket) {
                        operationx->setSize(size);
@@ -131,7 +131,7 @@ void BlurNode::convertToOperations(ExecutionSystem *graph, CompositorContext *co
                operation->setQuality(quality);
                graph->addOperation(operation);
                this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket());
-               addPreviewOperation(graph, operation->getOutputSocket());
+               addPreviewOperation(graph, context, operation->getOutputSocket());
 
                if (!connectedSizeSocket) {
                        operation->setSize(size);
index f6abbbb..a89ed9e 100644 (file)
@@ -35,5 +35,5 @@ void BokehImageNode::convertToOperations(ExecutionSystem *graph, CompositorConte
        this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket(0));
        graph->addOperation(operation);
        operation->setData((NodeBokehImage *)this->getbNode()->storage);
-       addPreviewOperation(graph, operation->getOutputSocket(0));
+       addPreviewOperation(graph, context, operation->getOutputSocket(0));
 }
index eab9218..c1511ee 100644 (file)
@@ -84,7 +84,7 @@ void ChannelMatteNode::convertToOperations(ExecutionSystem *graph, CompositorCon
        graph->addOperation(operationAlpha);
 
        addLink(graph, operation->getOutputSocket(), operationAlpha->getInputSocket(1));
-       addPreviewOperation(graph, operationAlpha->getOutputSocket());
+       addPreviewOperation(graph, context, operationAlpha->getOutputSocket());
 
        if (outputSocketImage->isConnected()) {
                outputSocketImage->relinkConnections(operationAlpha->getOutputSocket());
index 0fb0915..4c4b77b 100644 (file)
@@ -65,7 +65,7 @@ void ChromaMatteNode::convertToOperations(ExecutionSystem *graph, CompositorCont
        addLink(graph, operation->getOutputSocket(), operationAlpha->getInputSocket(1));
 
        graph->addOperation(operationAlpha);
-       addPreviewOperation(graph, operationAlpha->getOutputSocket());
+       addPreviewOperation(graph, context, operationAlpha->getOutputSocket());
 
        if (outputSocketImage->isConnected()) {
                outputSocketImage->relinkConnections(operationAlpha->getOutputSocket());
index 38ab6ba..54e6762 100644 (file)
@@ -62,7 +62,7 @@ void ColorMatteNode::convertToOperations(ExecutionSystem *graph, CompositorConte
        addLink(graph, operationRGBToHSV_Image->getInputSocket(0)->getConnection()->getFromSocket(), operationAlpha->getInputSocket(0));
        addLink(graph, operation->getOutputSocket(), operationAlpha->getInputSocket(1));
        graph->addOperation(operationAlpha);
-       addPreviewOperation(graph, operationAlpha->getOutputSocket());
+       addPreviewOperation(graph, context, operationAlpha->getOutputSocket());
 
        if (outputSocketImage->isConnected()) {
                outputSocketImage->relinkConnections(operationAlpha->getOutputSocket());
index d0d66a8..e331375 100644 (file)
@@ -45,5 +45,5 @@ void CompositorNode::convertToOperations(ExecutionSystem *graph, CompositorConte
        alphaSocket->relinkConnections(compositorOperation->getInputSocket(1));
        depthSocket->relinkConnections(compositorOperation->getInputSocket(2));
        graph->addOperation(compositorOperation);
-       addPreviewOperation(graph, compositorOperation->getInputSocket(0));
+       addPreviewOperation(graph, context, compositorOperation->getInputSocket(0));
 }
index 603ddcd..a97714c 100644 (file)
@@ -44,7 +44,7 @@ void DespeckleNode::convertToOperations(ExecutionSystem *graph, CompositorContex
        inputImageSocket->relinkConnections(operation->getInputSocket(0), 1, graph);
        inputSocket->relinkConnections(operation->getInputSocket(1), 0, graph);
        outputSocket->relinkConnections(operation->getOutputSocket());
-       addPreviewOperation(graph, operation->getOutputSocket(0));
+       addPreviewOperation(graph, context, operation->getOutputSocket(0));
 
        graph->addOperation(operation);
 }
index 6dca049..b5ad07b 100644 (file)
@@ -51,5 +51,5 @@ void DifferenceMatteNode::convertToOperations(ExecutionSystem *graph, Compositor
        addLink(graph, operationSet->getOutputSocket(), operation->getInputSocket(1));
        outputSocketImage->relinkConnections(operation->getOutputSocket());
        graph->addOperation(operation);
-       addPreviewOperation(graph, operation->getOutputSocket());
+       addPreviewOperation(graph, context, operation->getOutputSocket());
 }
index cecc3bf..5bd2f78 100644 (file)
@@ -106,7 +106,7 @@ void DilateErodeNode::convertToOperations(ExecutionSystem *graph, CompositorCont
                graph->addOperation(operationy);
                addLink(graph, operationx->getOutputSocket(), operationy->getInputSocket(0));
                // addLink(graph, operationx->getInputSocket(1)->getConnection()->getFromSocket(), operationy->getInputSocket(1)); // no size input yet
-               addPreviewOperation(graph, operationy->getOutputSocket());
+               addPreviewOperation(graph, context, operationy->getOutputSocket());
 
                /* TODO? */
                /* see gaussian blue node for original usage */
index 87e7b9d..782c897 100644 (file)
@@ -77,7 +77,7 @@ void DistanceMatteNode::convertToOperations(ExecutionSystem *graph, CompositorCo
        addLink(graph, operation->getOutputSocket(), operationAlpha->getInputSocket(1));
 
        graph->addOperation(operationAlpha);
-       addPreviewOperation(graph, operationAlpha->getOutputSocket());
+       addPreviewOperation(graph, context, operationAlpha->getOutputSocket());
 
        if (outputSocketImage->isConnected()) {
                outputSocketImage->relinkConnections(operationAlpha->getOutputSocket());
index 021ec6c..990cdb4 100644 (file)
@@ -77,7 +77,7 @@ void FilterNode::convertToOperations(ExecutionSystem *graph, CompositorContext *
        inputImageSocket->relinkConnections(operation->getInputSocket(0), 1, graph);
        inputSocket->relinkConnections(operation->getInputSocket(1), 0, graph);
        outputSocket->relinkConnections(operation->getOutputSocket());
-       addPreviewOperation(graph, operation->getOutputSocket(0));
+       addPreviewOperation(graph, context, operation->getOutputSocket(0));
        
        graph->addOperation(operation);
 }
index 2d13ffb..4ebd28d 100644 (file)
@@ -111,7 +111,7 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
                                                                        break;
                                                        }
                                                        if (index == 0 && operation) {
-                                                               addPreviewOperation(graph, operation->getOutputSocket());
+                                                               addPreviewOperation(graph, context, operation->getOutputSocket());
                                                        }
                                                }
                                        }
@@ -134,7 +134,7 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
                        operation->setImageUser(imageuser);
                        operation->setFramenumber(framenumber);
                        graph->addOperation(operation);
-                       addPreviewOperation(graph, operation->getOutputSocket());
+                       addPreviewOperation(graph, context, operation->getOutputSocket());
                }
                
                if (numberOfOutputs > 1) {
index be949e2..4656e00 100644 (file)
@@ -55,7 +55,7 @@ void LuminanceMatteNode::convertToOperations(ExecutionSystem *graph, CompositorC
        addLink(graph, rgbToYUV->getInputSocket(0)->getConnection()->getFromSocket(), operation->getInputSocket(0));
        addLink(graph, operationSet->getOutputSocket(), operation->getInputSocket(1));
        graph->addOperation(operation);
-       addPreviewOperation(graph, operation->getOutputSocket());
+       addPreviewOperation(graph, context, operation->getOutputSocket());
 
        if (outputSocketImage->isConnected()) {
                outputSocketImage->relinkConnections(operation->getOutputSocket());
index 7aeaaf5..ab4e464 100644 (file)
@@ -128,7 +128,7 @@ void MixNode::convertToOperations(ExecutionSystem *graph, CompositorContext *con
        color1Socket->relinkConnections(convertProg->getInputSocket(1), 1, graph);
        color2Socket->relinkConnections(convertProg->getInputSocket(2), 2, graph);
        outputSocket->relinkConnections(convertProg->getOutputSocket(0));
-       addPreviewOperation(graph, convertProg->getOutputSocket(0));
+       addPreviewOperation(graph, context, convertProg->getOutputSocket(0));
        
        convertProg->getInputSocket(2)->setResizeMode(color2Socket->getResizeMode());
        
index 6d5b9bb..5d5e68f 100644 (file)
@@ -62,25 +62,9 @@ void MovieClipNode::convertToOperations(ExecutionSystem *graph, CompositorContex
        // always connect the output image
        MovieClipOperation *operation = new MovieClipOperation();
        
-       if (ibuf && context->isColorManaged() && ibuf->profile == IB_PROFILE_NONE) {
-               ConvertColorProfileOperation *converter = new ConvertColorProfileOperation();
-               converter->setFromColorProfile(IB_PROFILE_LINEAR_RGB);
-               converter->setToColorProfile(IB_PROFILE_SRGB);
-               addLink(graph, operation->getOutputSocket(), converter->getInputSocket(0));
-               addPreviewOperation(graph, converter->getOutputSocket());
-               if (outputMovieClip->isConnected()) {
-                       outputMovieClip->relinkConnections(converter->getOutputSocket());
-               }
-               graph->addOperation(converter);
-               if (ibuf) {
-                       converter->setPredivided(ibuf->flags & IB_cm_predivide);
-               }
-       }
-       else {
-               addPreviewOperation(graph, operation->getOutputSocket());
-               if (outputMovieClip->isConnected()) {
-                       outputMovieClip->relinkConnections(operation->getOutputSocket());
-               }
+       addPreviewOperation(graph, context, operation->getOutputSocket());
+       if (outputMovieClip->isConnected()) {
+               outputMovieClip->relinkConnections(operation->getOutputSocket());
        }
 
        operation->setMovieClip(movieClip);
index b8cee29..921b9e6 100644 (file)
@@ -62,7 +62,7 @@ void OutputFileNode::convertToOperations(ExecutionSystem *graph, CompositorConte
                                input->relinkConnections(outputOperation->getInputSocket(i));
                        }
                }
-               if (hasConnections) addPreviewOperation(graph, outputOperation->getInputSocket(0));
+               if (hasConnections) addPreviewOperation(graph, context, outputOperation->getInputSocket(0));
                
                graph->addOperation(outputOperation);
        }
@@ -80,11 +80,12 @@ void OutputFileNode::convertToOperations(ExecutionSystem *graph, CompositorConte
                                BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
                                
                                OutputSingleLayerOperation *outputOperation = new OutputSingleLayerOperation(
-                                       context->getRenderData(), context->getbNodeTree(), input->getDataType(), format, path);
+                                       context->getRenderData(), context->getbNodeTree(), input->getDataType(), format, path,
+                                       context->getViewSettings(), context->getDisplaySettings());
                                input->relinkConnections(outputOperation->getInputSocket(0));
                                graph->addOperation(outputOperation);
                                if (!previewAdded) {
-                                       addPreviewOperation(graph, outputOperation->getInputSocket(0));
+                                       addPreviewOperation(graph, context, outputOperation->getInputSocket(0));
                                        previewAdded = true;
                                }
                        }
index dfb46af..b57e997 100644 (file)
@@ -52,7 +52,7 @@ RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
        /* pass */
 }
 
-void RenderLayersNode::testSocketConnection(ExecutionSystem *system, int outputSocketNumber, RenderLayersBaseProg *operation)
+void RenderLayersNode::testSocketConnection(ExecutionSystem *system, CompositorContext *context, int outputSocketNumber, RenderLayersBaseProg *operation)
 {
        OutputSocket *outputSocket = this->getOutputSocket(outputSocketNumber);
        Scene *scene = (Scene *)this->getbNode()->id;
@@ -64,7 +64,7 @@ void RenderLayersNode::testSocketConnection(ExecutionSystem *system, int outputS
                outputSocket->relinkConnections(operation->getOutputSocket());
                system->addOperation(operation);
                if (outputSocketNumber == 0) { // only do for image socket if connected
-                       addPreviewOperation(system, operation->getOutputSocket());
+                       addPreviewOperation(system, context, operation->getOutputSocket());
                }
        }
        else {
@@ -72,7 +72,7 @@ void RenderLayersNode::testSocketConnection(ExecutionSystem *system, int outputS
                        system->addOperation(operation);
                        operation->setScene(scene);
                        operation->setLayerId(layerId);
-                       addPreviewOperation(system, operation->getOutputSocket());
+                       addPreviewOperation(system, context, operation->getOutputSocket());
                }
                else {
                        delete operation;
@@ -82,34 +82,34 @@ void RenderLayersNode::testSocketConnection(ExecutionSystem *system, int outputS
 
 void RenderLayersNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
 {
-       testSocketConnection(graph, 0, new RenderLayersColorProg());
-       testSocketConnection(graph, 1, new RenderLayersAlphaProg());
-       testSocketConnection(graph, 2, new RenderLayersDepthProg());
-       testSocketConnection(graph, 3, new RenderLayersNormalOperation());
-       testSocketConnection(graph, 4, new RenderLayersUVOperation());
-       testSocketConnection(graph, 5, new RenderLayersSpeedOperation());
-       testSocketConnection(graph, 6, new RenderLayersColorOperation());
-       testSocketConnection(graph, 7, new RenderLayersDiffuseOperation());
-       testSocketConnection(graph, 8, new RenderLayersSpecularOperation());
-       testSocketConnection(graph, 9, new RenderLayersShadowOperation());
-       testSocketConnection(graph, 10, new RenderLayersAOOperation());
-       testSocketConnection(graph, 11, new RenderLayersReflectionOperation());
-       testSocketConnection(graph, 12, new RenderLayersRefractionOperation());
-       testSocketConnection(graph, 13, new RenderLayersIndirectOperation());
-       testSocketConnection(graph, 14, new RenderLayersObjectIndexOperation());
-       testSocketConnection(graph, 15, new RenderLayersMaterialIndexOperation());
-       testSocketConnection(graph, 16, new RenderLayersMistOperation());
-       testSocketConnection(graph, 17, new RenderLayersEmitOperation());
-       testSocketConnection(graph, 18, new RenderLayersEnvironmentOperation());
+       testSocketConnection(graph, context, 0, new RenderLayersColorProg());
+       testSocketConnection(graph, context, 1, new RenderLayersAlphaProg());
+       testSocketConnection(graph, context, 2, new RenderLayersDepthProg());
+       testSocketConnection(graph, context, 3, new RenderLayersNormalOperation());
+       testSocketConnection(graph, context, 4, new RenderLayersUVOperation());
+       testSocketConnection(graph, context, 5, new RenderLayersSpeedOperation());
+       testSocketConnection(graph, context, 6, new RenderLayersColorOperation());
+       testSocketConnection(graph, context, 7, new RenderLayersDiffuseOperation());
+       testSocketConnection(graph, context, 8, new RenderLayersSpecularOperation());
+       testSocketConnection(graph, context, 9, new RenderLayersShadowOperation());
+       testSocketConnection(graph, context, 10, new RenderLayersAOOperation());
+       testSocketConnection(graph, context, 11, new RenderLayersReflectionOperation());
+       testSocketConnection(graph, context, 12, new RenderLayersRefractionOperation());
+       testSocketConnection(graph, context, 13, new RenderLayersIndirectOperation());
+       testSocketConnection(graph, context, 14, new RenderLayersObjectIndexOperation());
+       testSocketConnection(graph, context, 15, new RenderLayersMaterialIndexOperation());
+       testSocketConnection(graph, context, 16, new RenderLayersMistOperation());
+       testSocketConnection(graph, context, 17, new RenderLayersEmitOperation());
+       testSocketConnection(graph, context, 18, new RenderLayersEnvironmentOperation());
        
        // cycles passes
-       testSocketConnection(graph, 19, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_DIRECT));
-       testSocketConnection(graph, 20, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_INDIRECT));
-       testSocketConnection(graph, 21, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_COLOR));
-       testSocketConnection(graph, 22, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_DIRECT));
-       testSocketConnection(graph, 23, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_INDIRECT));
-       testSocketConnection(graph, 24, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_COLOR));
-       testSocketConnection(graph, 25, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_DIRECT));
-       testSocketConnection(graph, 26, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_INDIRECT));
-       testSocketConnection(graph, 27, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_COLOR));
+       testSocketConnection(graph, context, 19, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_DIRECT));
+       testSocketConnection(graph, context, 20, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_INDIRECT));
+       testSocketConnection(graph, context, 21, new RenderLayersCyclesOperation(SCE_PASS_DIFFUSE_COLOR));
+       testSocketConnection(graph, context, 22, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_DIRECT));
+       testSocketConnection(graph, context, 23, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_INDIRECT));
+       testSocketConnection(graph, context, 24, new RenderLayersCyclesOperation(SCE_PASS_GLOSSY_COLOR));
+       testSocketConnection(graph, context, 25, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_DIRECT));
+       testSocketConnection(graph, context, 26, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_INDIRECT));
+       testSocketConnection(graph, context, 27, new RenderLayersCyclesOperation(SCE_PASS_TRANSM_COLOR));
 }
index 32672c8..9bd7462 100644 (file)
@@ -33,5 +33,5 @@ public:
        RenderLayersNode(bNode *editorNode);
        void convertToOperations(ExecutionSystem *graph, CompositorContext *context);
 private:
-       void testSocketConnection(ExecutionSystem *graph, int outputSocketNumber, RenderLayersBaseProg *operation);
+       void testSocketConnection(ExecutionSystem *graph, CompositorContext *context, int outputSocketNumber, RenderLayersBaseProg *operation);
 };
index 388466c..37b888b 100644 (file)
@@ -39,13 +39,14 @@ void SplitViewerNode::convertToOperations(ExecutionSystem *graph, CompositorCont
        ImageUser *imageUser = (ImageUser *) this->getbNode()->storage;
        if (image1Socket->isConnected() && image2Socket->isConnected()) {
                SplitViewerOperation *splitViewerOperation = new SplitViewerOperation();
-               splitViewerOperation->setColorManagement(context->getRenderData()->color_mgt_flag & R_COLOR_MANAGEMENT);
-               splitViewerOperation->setColorPredivide(context->getRenderData()->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE);
                splitViewerOperation->setImage(image);
                splitViewerOperation->setImageUser(imageUser);
                splitViewerOperation->setActive((this->getbNode()->flag & NODE_DO_OUTPUT) && this->isInActiveGroup());
                splitViewerOperation->setSplitPercentage(this->getbNode()->custom1);
 
+               splitViewerOperation->setViewSettings(context->getViewSettings());
+               splitViewerOperation->setDisplaySettings(context->getDisplaySettings());
+
                /* defaults - the viewer node has these options but not exposed for split view
                 * we could use the split to define an area of interest on one axis at least */
                splitViewerOperation->setChunkOrder(COM_ORDER_OF_CHUNKS_DEFAULT);
@@ -55,7 +56,7 @@ void SplitViewerNode::convertToOperations(ExecutionSystem *graph, CompositorCont
                splitViewerOperation->setXSplit(!this->getbNode()->custom2);
                image1Socket->relinkConnections(splitViewerOperation->getInputSocket(0), 0, graph);
                image2Socket->relinkConnections(splitViewerOperation->getInputSocket(1), 1, graph);
-               addPreviewOperation(graph, splitViewerOperation->getInputSocket(0));
+               addPreviewOperation(graph, context, splitViewerOperation->getInputSocket(0));
                graph->addOperation(splitViewerOperation);
        }
 }
index b035e0a..5b386a5 100644 (file)
@@ -40,7 +40,7 @@ void TextureNode::convertToOperations(ExecutionSystem *system, CompositorContext
        operation->setTexture(texture);
        operation->setRenderData(context->getRenderData());
        system->addOperation(operation);
-       addPreviewOperation(system, operation->getOutputSocket());
+       addPreviewOperation(system, context, operation->getOutputSocket());
 
        if (this->getOutputSocket(0)->isConnected()) {
                TextureAlphaOperation *alphaOperation = new TextureAlphaOperation();
index 88ce0ff..d67e9e2 100644 (file)
@@ -40,8 +40,6 @@ void ViewerNode::convertToOperations(ExecutionSystem *graph, CompositorContext *
        ImageUser *imageUser = (ImageUser *) this->getbNode()->storage;
        bNode *editorNode = this->getbNode();
        ViewerOperation *viewerOperation = new ViewerOperation();
-       viewerOperation->setColorManagement(context->getRenderData()->color_mgt_flag & R_COLOR_MANAGEMENT);
-       viewerOperation->setColorPredivide(context->getRenderData()->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE);
        viewerOperation->setbNodeTree(context->getbNodeTree());
        viewerOperation->setImage(image);
        viewerOperation->setImageUser(imageUser);
@@ -50,6 +48,9 @@ void ViewerNode::convertToOperations(ExecutionSystem *graph, CompositorContext *
        viewerOperation->setCenterX(editorNode->custom3);
        viewerOperation->setCenterY(editorNode->custom4);
 
+       viewerOperation->setViewSettings(context->getViewSettings());
+       viewerOperation->setDisplaySettings(context->getDisplaySettings());
+
        viewerOperation->setResolutionInputSocketIndex(0);
        if (!imageSocket->isConnected())
        {
@@ -62,5 +63,5 @@ void ViewerNode::convertToOperations(ExecutionSystem *graph, CompositorContext *
        alphaSocket->relinkConnections(viewerOperation->getInputSocket(1));
        depthSocket->relinkConnections(viewerOperation->getInputSocket(2));
        graph->addOperation(viewerOperation);
-       addPreviewOperation(graph, viewerOperation->getInputSocket(0));
+       addPreviewOperation(graph, context, viewerOperation->getInputSocket(0));
 }
index b72875a..21ecfdb 100644 (file)
 #include "BKE_global.h"
 #include "BKE_main.h"
 
+#include "DNA_color_types.h"
+
 extern "C" {
        #include "MEM_guardedalloc.h"
        #include "IMB_imbuf.h"
+       #include "IMB_colormanagement.h"
        #include "IMB_imbuf_types.h"
 }
 
@@ -91,7 +94,8 @@ static void write_buffer_rect(rcti *rect, const bNodeTree *tree,
 
 
 OutputSingleLayerOperation::OutputSingleLayerOperation(
-    const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path)
+    const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+    const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
 {
        this->m_rd = rd;
        this->m_tree = tree;
@@ -104,6 +108,9 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
        
        this->m_format = format;
        BLI_strncpy(this->m_path, path, sizeof(this->m_path));
+
+       this->m_viewSettings = viewSettings;
+       this->m_displaySettings = displaySettings;
 }
 
 void OutputSingleLayerOperation::initExecution()
@@ -131,8 +138,7 @@ void OutputSingleLayerOperation::deinitExecution()
                ibuf->mall |= IB_rectfloat; 
                ibuf->dither = this->m_rd->dither_intensity;
                
-               if (this->m_rd->color_mgt_flag & R_COLOR_MANAGEMENT)
-                       ibuf->profile = IB_PROFILE_LINEAR_RGB;
+               IMB_display_buffer_to_imbuf_rect(ibuf, m_viewSettings, m_displaySettings);
                
                BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format->imtype,
                                  (this->m_rd->scemode & R_EXTENSION), true);
index 532242c..69d1ad4 100644 (file)
@@ -28,6 +28,8 @@
 #include "BLI_rect.h"
 #include "BLI_path_util.h"
 
+#include "DNA_color_types.h"
+
 #include "intern/openexr/openexr_multi.h"
 
 /* Writes the image to a single-layer file. */
@@ -43,8 +45,11 @@ private:
        DataType m_datatype;
        SocketReader *m_imageInput;
 
+       const ColorManagedViewSettings *m_viewSettings;
+       const ColorManagedDisplaySettings *m_displaySettings;
 public:
-       OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path);
+       OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+                                  const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
        
        void executeRegion(rcti *rect, unsigned int tileNumber);
        bool isOutputOperation(bool rendering) const { return true; }
index aff374c..6e58b27 100644 (file)
@@ -35,16 +35,19 @@ extern "C" {
        #include "MEM_guardedalloc.h"
        #include "IMB_imbuf.h"
        #include "IMB_imbuf_types.h"
+       #include "IMB_colormanagement.h"
 }
 
 
-PreviewOperation::PreviewOperation() : NodeOperation()
+PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings) : NodeOperation()
 {
        this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
        this->m_outputBuffer = NULL;
        this->m_input = NULL;
        this->m_divider = 1.0f;
        this->m_node = NULL;
+       this->m_viewSettings = viewSettings;
+       this->m_displaySettings = displaySettings;
 }
 
 void PreviewOperation::initExecution()
@@ -82,6 +85,10 @@ void PreviewOperation::executeRegion(rcti *rect, unsigned int tileNumber)
 {
        int offset;
        float color[4];
+       struct ColormanageProcessor *cm_processor;
+
+       cm_processor = IMB_colormanagement_display_processor_new(this->m_viewSettings, this->m_displaySettings);
+
        for (int y = rect->ymin; y < rect->ymax; y++) {
                offset = (y * getWidth() + rect->xmin) * 4;
                for (int x = rect->xmin; x < rect->xmax; x++) {
@@ -93,11 +100,13 @@ void PreviewOperation::executeRegion(rcti *rect, unsigned int tileNumber)
                        color[2] = 0.0f;
                        color[3] = 1.0f;
                        this->m_input->read(color, rx, ry, COM_PS_NEAREST);
-                       linearrgb_to_srgb_v4(color, color);
+                       IMB_colormanagement_processor_apply_v4(cm_processor, color);
                        F4TOCHAR4(color, this->m_outputBuffer + offset);
                        offset += 4;
                }
        }
+
+       IMB_colormanagement_processor_free(cm_processor);
 }
 bool PreviewOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 {
index ffd80ff..9e774d0 100644 (file)
@@ -24,6 +24,7 @@
 #define _COM_PreviewOperation_h
 #include "COM_NodeOperation.h"
 #include "DNA_image_types.h"
+#include "DNA_color_types.h"
 #include "BLI_rect.h"
 
 class PreviewOperation : public NodeOperation {
@@ -37,8 +38,10 @@ protected:
        SocketReader *m_input;
        float m_divider;
 
+       const ColorManagedViewSettings *m_viewSettings;
+       const ColorManagedDisplaySettings *m_displaySettings;
 public:
-       PreviewOperation();
+       PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
        bool isOutputOperation(bool rendering) const { return true; }
        void initExecution();
        void deinitExecution();
index d59d1f9..7325e32 100644 (file)
@@ -62,7 +62,6 @@ void SplitViewerOperation::deinitExecution()
 void SplitViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
 {
        float *buffer = this->m_outputBuffer;
-       unsigned char *bufferDisplay = this->m_outputBufferDisplay;
        
        if (!buffer) return;
        int x1 = rect->xmin;
@@ -76,7 +75,6 @@ void SplitViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
        for (y = y1; y < y2; y++) {
                for (x = x1; x < x2; x++) {
                        bool image1;
-                       float srgb[4];
                        image1 = this->m_xSplit ? x > perc : y > perc;
                        if (image1) {
                                this->m_image1Input->read(&(buffer[offset]), x, y, COM_PS_NEAREST);
@@ -84,21 +82,7 @@ void SplitViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
                        else {
                                this->m_image2Input->read(&(buffer[offset]), x, y, COM_PS_NEAREST);
                        }
-                       /// @todo: linear conversion only when scene color management is selected, also check predivide.
-                       if (this->m_doColorManagement) {
-                               if (this->m_doColorPredivide) {
-                                       linearrgb_to_srgb_predivide_v4(srgb, buffer + offset);
-                               }
-                               else {
-                                       linearrgb_to_srgb_v4(srgb, buffer + offset);
-                               }
-                       }
-                       else {
-                               copy_v4_v4(srgb, buffer + offset);
-                       }
-       
-                       rgba_float_to_uchar(bufferDisplay + offset, srgb);
-       
+
                        offset += 4;
                }
                offset += (this->getWidth() - (x2 - x1)) * 4;
index 1d913b9..d9ca131 100644 (file)
@@ -44,10 +44,10 @@ ViewerBaseOperation::ViewerBaseOperation() : NodeOperation()
        this->setImageUser(NULL);
        this->m_outputBuffer = NULL;
        this->m_depthBuffer = NULL;
-       this->m_outputBufferDisplay = NULL;
        this->m_active = false;
-       this->m_doColorManagement = true;
        this->m_doDepthBuffer = false;
+       this->m_viewSettings = NULL;
+       this->m_displaySettings = NULL;
 }
 
 void ViewerBaseOperation::initExecution()
@@ -71,11 +71,10 @@ void ViewerBaseOperation::initImage()
                IMB_freezbuffloatImBuf(ibuf);
                ibuf->x = getWidth();
                ibuf->y = getHeight();
-               imb_addrectImBuf(ibuf);
                imb_addrectfloatImBuf(ibuf);
                anImage->ok = IMA_OK_LOADED;
 
-               IMB_display_buffer_invalidate(ibuf);
+               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
 
                BLI_unlock_thread(LOCK_DRAW_IMAGE);
        }
@@ -88,7 +87,6 @@ void ViewerBaseOperation::initImage()
 
        /* now we combine the input with ibuf */
        this->m_outputBuffer = ibuf->rect_float;
-       this->m_outputBufferDisplay = (unsigned char *)ibuf->rect;
 
        /* needed for display buffer update
         *
@@ -107,7 +105,8 @@ void ViewerBaseOperation::initImage()
 }
 void ViewerBaseOperation:: updateImage(rcti *rect)
 {
-       IMB_partial_display_buffer_update(this->m_ibuf, this->m_outputBuffer, getWidth(), 0, 0,
+       IMB_partial_display_buffer_update(this->m_ibuf, this->m_outputBuffer, NULL, getWidth(), 0, 0,
+                                         this->m_viewSettings, this->m_displaySettings,
                                          rect->xmin, rect->ymin, rect->xmax, rect->ymax);
 
        WM_main_add_notifier(NC_WINDOW | ND_DRAW, NULL);
index 383f69b..f7d479e 100644 (file)
@@ -30,7 +30,6 @@ class ViewerBaseOperation : public NodeOperation {
 protected:
        float *m_outputBuffer;
        float *m_depthBuffer;
-       unsigned char *m_outputBufferDisplay;
        Image *m_image;
        ImageUser *m_imageUser;
        void *m_lock;
@@ -38,11 +37,12 @@ protected:
        float m_centerX;
        float m_centerY;
        OrderOfChunks m_chunkOrder;
-       bool m_doColorManagement;
-       bool m_doColorPredivide;
        bool m_doDepthBuffer;
        ImBuf *m_ibuf;
 
+       const ColorManagedViewSettings *m_viewSettings;
+       const ColorManagedDisplaySettings *m_displaySettings;
+
 public:
        bool isOutputOperation(bool rendering) const { return isActiveViewerOutput(); }
        void initExecution();
@@ -58,10 +58,10 @@ public:
        float getCenterY() { return this->m_centerY; }
        OrderOfChunks getChunkOrder() { return this->m_chunkOrder; }
        const CompositorPriority getRenderPriority() const;
-       void setColorManagement(bool doColorManagement) { this->m_doColorManagement = doColorManagement; }
-       void setColorPredivide(bool doColorPredivide) { this->m_doColorPredivide = doColorPredivide; }
        bool isViewerOperation() { return true; }
-               
+
+       void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; }
+       void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; }
 protected:
        ViewerBaseOperation();
        void updateImage(rcti *rect);
index b85b86b..576d5da 100644 (file)
@@ -72,7 +72,6 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
 {
        float *buffer = this->m_outputBuffer;
        float *depthbuffer = this->m_depthBuffer;
-       unsigned char *bufferDisplay = this->m_outputBufferDisplay;
        if (!buffer) return;
        const int x1 = rect->xmin;
        const int y1 = rect->ymin;
@@ -82,7 +81,7 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
        const int offsetadd4 = offsetadd * 4;
        int offset = (y1 * this->getWidth() + x1);
        int offset4 = offset * 4;
-       float alpha[4], srgb[4], depth[4];
+       float alpha[4], depth[4];
        int x;
        int y;
        bool breaked = false;
@@ -98,19 +97,6 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
                                this->m_depthInput->read(depth, x, y, COM_PS_NEAREST);
                                depthbuffer[offset] = depth[0];
                        } 
-                       if (this->m_doColorManagement) {
-                               if (this->m_doColorPredivide) {
-                                       linearrgb_to_srgb_predivide_v4(srgb, buffer + offset4);
-                               }
-                               else {
-                                       linearrgb_to_srgb_v4(srgb, buffer + offset4);
-                               }
-                       }
-                       else {
-                               copy_v4_v4(srgb, buffer + offset4);
-                       }
-
-                       rgba_float_to_uchar(bufferDisplay + offset4, srgb);
 
                        offset ++;
                        offset4 += 4;
index 7f40024..b1bccfa 100644 (file)
@@ -282,10 +282,12 @@ int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
 
 int ED_view3d_context_activate(struct bContext *C);
 void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
-                              int winx, int winy, float viewmat[][4], float winmat[][4], int do_bgpic);
+                              int winx, int winy, float viewmat[][4], float winmat[][4], int do_bgpic, int colormanage_background);
 
-struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, int draw_background, char err_out[256]);
-struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, int draw_background, char err_out[256]);
+struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
+                                             int draw_background, int colormanage_background, char err_out[256]);
+struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
+                                                    int draw_background, int colormanage_background, char err_out[256]);
 
 
 struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
index 718ed40..a878632 100644 (file)
@@ -75,6 +75,8 @@
 
 #include "BPY_extern.h"
 
+#include "IMB_colormanagement.h"
+
 #include "interface_intern.h"
 
 #define MENU_WIDTH          120
@@ -2137,7 +2139,14 @@ uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, shor
        block->evil_C = (void *)C;  /* XXX */
 
        if (scn) {
-               block->color_profile = (scn->r.color_mgt_flag & R_COLOR_MANAGEMENT);
+               block->color_profile = TRUE;
+
+               /* store display device name, don't lookup for transformations yet
+                * block could be used for non-color displays where looking up for transformation
+                * would slow down redraw, so only lookup for actual transform when it's indeed
+                * needed
+                */
+               block->display_device = scn->display_settings.display_device;
 
                /* copy to avoid crash when scene gets deleted with ui still open */
                block->unit = MEM_mallocN(sizeof(scn->unit), "UI UnitSettings");
@@ -2574,6 +2583,25 @@ void ui_block_do_align(uiBlock *block)
        }
 }
 
+struct ColorManagedDisplay *ui_block_display_get(uiBlock *block)
+{
+       return IMB_colormanagement_display_get_named(block->display_device);
+}
+
+void ui_block_to_display_space_v3(uiBlock *block, float pixel[3])
+{
+       struct ColorManagedDisplay *display = ui_block_display_get(block);
+
+       IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
+}
+
+void ui_block_to_scene_linear_v3(uiBlock *block, float pixel[3])
+{
+       struct ColorManagedDisplay *display = ui_block_display_get(block);
+
+       IMB_colormanagement_display_to_scene_linear_v3(pixel, display);
+}
+
 /**
  * \brief ui_def_but is the function that draws many button types
  *
index 77dbbc8..f535c3c 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -1110,10 +1111,14 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect)
        float v3[2], v1[2], v2[2], v1a[2], v2a[2];
        int a;
        float pos, colf[4] = {0, 0, 0, 0}; /* initialize in case the colorband isn't valid */
-               
+       struct ColorManagedDisplay *display = NULL;
+
        coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
        if (coba == NULL) return;
-       
+
+       if (but->block->color_profile)
+               display = ui_block_display_get(but->block);
+
        x1 = rect->xmin;
        y1 = rect->ymin;
        sizex = rect->xmax - x1;
@@ -1146,8 +1151,8 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect)
        for (a = 1; a <= sizex; a++) {
                pos = ((float)a) / (sizex - 1);
                do_colorband(coba, pos, colf);
-               if (but->block->color_profile != BLI_PR_NONE)
-                       linearrgb_to_srgb_v3_v3(colf, colf);
+               if (display)
+                       IMB_colormanagement_scene_linear_to_display_v3(colf, display);
                
                v1[0] = v2[0] = x1 + a;
                
index 17486ed..a1a6e34 100644 (file)
@@ -3158,7 +3158,7 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
 
        if (but->rnaprop) {
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
-                       color_profile = BLI_PR_NONE;
+                       color_profile = FALSE;
        }
 
        ui_get_but_vectorf(but, rgb);
@@ -3200,8 +3200,10 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
                        /* exception only for value strip - use the range set in but->min/max */
                        hsv[2] = y * (but->softmax - but->softmin) + but->softmin;
 
-                       if (color_profile)
+                       if (color_profile) {
+                               /* OCIO_TODO: how to handle this situation? */
                                hsv[2] = srgb_to_linearrgb(hsv[2]);
+                       }
 
                        if (hsv[2] > but->softmax)
                                hsv[2] = but->softmax;
@@ -3229,7 +3231,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, wmNDOF
        
        if (but->rnaprop) {
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
-                       color_profile = BLI_PR_NONE;
+                       color_profile = FALSE;
        }
 
        ui_get_but_vectorf(but, rgb);
@@ -3263,8 +3265,10 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, wmNDOF
                        /* exception only for value strip - use the range set in but->min/max */
                        hsv[2] += ndof->rx * sensitivity;
                        
-                       if (color_profile)
+                       if (color_profile) {
+                               /* OCIO_TODO: how to handle this situation? */
                                hsv[2] = srgb_to_linearrgb(hsv[2]);
+                       }
                        
                        CLAMP(hsv[2], but->softmin, but->softmax);
                default:
index a5e4fa5..6999f8e 100644 (file)
@@ -342,7 +342,12 @@ struct uiBlock {
 
        struct UnitSettings *unit;  /* unit system, used a lot for numeric buttons so include here rather then fetching through the scene every time. */
        float _hsv[3];              /* XXX, only access via ui_block_hsv_get() */
+
        char color_profile;         /* color profile for correcting linear colors for display */
+
+       char *display_device;       /* display devide name used to display this block,
+                                    * used by color widgets to transform colors from/to scene linear
+                                    */
 };
 
 typedef struct uiSafetyRct {
@@ -392,6 +397,10 @@ extern void ui_bounds_block(uiBlock *block);
 extern void ui_block_translate(uiBlock *block, int x, int y);
 extern void ui_block_do_align(uiBlock *block);
 
+extern struct ColorManagedDisplay *ui_block_display_get(uiBlock *block);
+void ui_block_to_display_space_v3(uiBlock *block, float pixel[3]);
+void ui_block_to_scene_linear_v3(uiBlock *block, float pixel[3]);
+
 /* interface_regions.c */
 
 struct uiPopupBlockHandle {
index e8b8959..7277923 100644 (file)
@@ -58,6 +58,8 @@
 
 #include "UI_interface.h"
 
+#include "IMB_colormanagement.h"
+
 #include "interface_intern.h"
 
 #include "WM_api.h"
@@ -75,7 +77,7 @@
 /* ********************************************************** */
 
 typedef struct Eyedropper {
-       short do_color_management;
+       struct ColorManagedDisplay *display;
 
        PointerRNA ptr;
        PropertyRNA *prop;
@@ -89,8 +91,6 @@ typedef struct Eyedropper {
 static int eyedropper_init(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
-       const int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
-
        Eyedropper *eye;
        
        op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
@@ -106,7 +106,12 @@ static int eyedropper_init(bContext *C, wmOperator *op)
                return FALSE;
        }
 
-       eye->do_color_management = (color_manage && RNA_property_subtype(eye->prop) == PROP_COLOR);
+       if (RNA_property_subtype(eye->prop) == PROP_COLOR) {
+               const char *display_device;
+
+               display_device = scene->display_settings.display_device;
+               eye->display = IMB_colormanagement_display_get_named(display_device);
+       }
 
        return TRUE;
 }
@@ -194,9 +199,10 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3
        /* to maintain alpha */
        RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
 
-       /* convert from screen (srgb) space to linear rgb space */
-       if (eye->do_color_management) {
-               srgb_to_linearrgb_v3_v3(col_conv, col);
+       /* convert from display space to linear rgb space */
+       if (eye->display) {
+               copy_v3_v3(col_conv, col);
+               IMB_colormanagement_display_to_scene_linear_v3(col_conv, eye->display);
        }
        else {
                copy_v3_v3(col_conv, col);
index bebc80c..ea0838c 100644 (file)
@@ -66,6 +66,8 @@
 
 #include "ED_screen.h"
 
+#include "IMB_colormanagement.h"
+
 #include "interface_intern.h"
 
 #define MENU_SEPR_HEIGHT    6
@@ -1900,11 +1902,15 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3])
 {
        uiBut *bt;
        float *hsv = ui_block_hsv_get(block);
+       struct ColorManagedDisplay *display = NULL;
        
        /* this is to keep the H and S value when V is equal to zero
         * and we are working in HSV mode, of course!
         */
        rgb_to_hsv_compat_v(rgb, hsv);
+
+       if (block->color_profile)
+               display = ui_block_display_get(block);
        
        /* this updates button strings, is hackish... but button pointers are on stack of caller function */
        for (bt = block->buttons.first; bt; bt = bt->next) {
@@ -1920,12 +1926,11 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3])
                        
                        /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
                        
-                       if (block->color_profile == BLI_PR_NONE) {
-                               copy_v3_v3(rgb_gamma, rgb);
-                       }
-                       else {
-                               /* make an sRGB version, for Hex code */
-                               linearrgb_to_srgb_v3_v3(rgb_gamma, rgb);
+                       copy_v3_v3(rgb_gamma, rgb);
+
+                       if (display) {
+                               /* make a display version, for Hex code */
+                               IMB_colormanagement_scene_linear_to_display_v3(rgb_gamma, display);
                        }
                        
                        if (rgb_gamma[0] > 1.0f) rgb_gamma[0] = modf(rgb_gamma[0], &intpart);
@@ -2004,9 +2009,9 @@ static void do_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
        hex_to_rgb(hexcol, rgb, rgb + 1, rgb + 2);
        
        /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
-       if (but->block->color_profile != BLI_PR_NONE) {
+       if (but->block->color_profile) {
                /* so we need to linearise it for Blender */
-               srgb_to_linearrgb_v3_v3(rgb, rgb);
+               ui_block_to_scene_linear_v3(but->block, rgb);
        }
        
        ui_update_block_buts_rgb(but->block, rgb);
@@ -2114,14 +2119,16 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
        
        /* existence of profile means storage is in linear color space, with display correction */
        /* XXX That tip message is not use anywhere! */
-       if (block->color_profile == BLI_PR_NONE) {
+       if (!block->color_profile) {
                BLI_strncpy(tip, N_("Value in Display Color Space"), sizeof(tip));
                copy_v3_v3(rgb_gamma, rgba);
        }
        else {
                BLI_strncpy(tip, N_("Value in Linear RGB Color Space"), sizeof(tip));
-               /* make an sRGB version, for Hex code */
-               linearrgb_to_srgb_v3_v3(rgb_gamma, rgba);
+
+               /* make a display version, for Hex code */
+               copy_v3_v3(rgb_gamma, rgba);
+               ui_block_to_display_space_v3(block, rgb_gamma);
        }
        
        /* sneaky way to check for alpha */
@@ -2246,7 +2253,7 @@ uiBlock *ui_block_func_COL(bContext *C, uiPopupBlockHandle *handle, void *arg_bu
        
        if (but->rnaprop) {
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
-                       block->color_profile = BLI_PR_NONE;
+                       block->color_profile = FALSE;
                }
        }
        
index 9131c27..522c567 100644 (file)
@@ -1872,7 +1872,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, rcti *rect)
        int color_profile = but->block->color_profile;
        
        if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
-               color_profile = BLI_PR_NONE;
+               color_profile = FALSE;
        
        radstep = 2.0f * (float)M_PI / (float)tot;
        centx = BLI_RCT_CENTER_X_FL(rect);
@@ -1894,8 +1894,10 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, rcti *rect)
         * Useful for color correction tools where you're only interested in hue. */
        if (but->flag & UI_BUT_COLOR_LOCK)
                hsv[2] = 1.f;
-       else if (color_profile)
+       else if (color_profile) {
+               /* OCIO_TODO: how to handle this situation? */
                hsv[2] = linearrgb_to_srgb(hsv[2]);
+       }
        
        hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
        
@@ -2137,14 +2139,16 @@ static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
        int color_profile = but->block->color_profile;
        
        if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
-               color_profile = BLI_PR_NONE;
+               color_profile = FALSE;
 
        ui_get_but_vectorf(but, rgb);
        rgb_to_hsv_v(rgb, hsv);
        v = hsv[2];
        
-       if (color_profile)
+       if (color_profile) {
+               /* OCIO_TODO: how to handle this situation? */
                v = linearrgb_to_srgb(v);
+       }
 
        /* map v from property range to [0,1] */
        range = but->softmax - but->softmin;
@@ -2529,7 +2533,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
 
        if (but->rnaprop) {
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
-                       color_profile = BLI_PR_NONE;
+                       color_profile = FALSE;
 
                if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
                        col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
@@ -2557,7 +2561,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
        }
        
        if (color_profile)
-               linearrgb_to_srgb_v3_v3(col, col);
+               ui_block_to_display_space_v3(but->block, col);
        
        rgba_float_to_uchar((unsigned char *)wcol->inner, col);
 
index 59cc782..f9b01a5 100644 (file)
@@ -69,6 +69,7 @@
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
 
 #include "GPU_draw.h" /* GPU_free_image */
 
@@ -685,7 +686,7 @@ static void apply_heights_data(void *bake_data)
                }
        }
 
-       ibuf->userflags = IB_RECT_INVALID;
+       ibuf->userflags = IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID;
 }
 
 static void free_heights_data(void *bake_data)
@@ -769,6 +770,8 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
                char *rrgb = (char *)ibuf->rect + pixel * 4;
                rrgb[3] = 255;
        }
+
+       ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
 }
 
 /* MultiresBake callback for normals' baking
@@ -826,6 +829,8 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
                rgb_float_to_uchar(rrgb, vec);
                rrgb[3] = 255;
        }
+
+       ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
 }
 
 static void count_images(MultiresBakeRender *bkr)
@@ -895,7 +900,7 @@ static void finish_images(MultiresBakeRender *bkr)
 
                RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, bkr->bake_filter);
 
-               ibuf->userflags |= IB_BITMAPDIRTY;
+               ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;;
 
                if (ibuf->rect_float)
                        ibuf->userflags |= IB_RECT_INVALID;
@@ -1366,6 +1371,7 @@ static void finish_bake_internal(BakeRender *bkr)
                                ImBuf *ibuf = BKE_image_get_ibuf(ima, NULL);
                                if (ibuf) {
                                        if (ibuf->userflags & IB_BITMAPDIRTY) {
+                                               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
                                                GPU_free_image(ima);
                                                imb_freemipmapImBuf(ibuf);
                                        }
index 04a43c4..ebacac9 100644 (file)
@@ -79,7 +79,7 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat
 {
        float *rectf = NULL;
        int ymin, ymax, xmin, xmax;
-       int rymin, rxmin, predivide, profile_from;
+       int rymin, rxmin;
        unsigned char *rectc;
 
        /* if renrect argument, we only refresh scanlines */
@@ -139,20 +139,8 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat
        rectf += 4 * (rr->rectx * ymin + xmin);
        rectc = (unsigned char *)(ibuf->rect + ibuf->x * rymin + rxmin);
 
-       if (scene && (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)) {
-               profile_from = IB_PROFILE_LINEAR_RGB;
-               predivide = (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE);
-       }
-       else {
-               profile_from = IB_PROFILE_SRGB;
-               predivide = 0;
-       }
-
-       IMB_buffer_byte_from_float(rectc, rectf,
-                                  4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide,
-                                  xmax, ymax, ibuf->x, rr->rectx);
-
-       IMB_partial_display_buffer_update(ibuf, rectf, rr->rectx, rxmin, rymin,
+       IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin,
+                                         &scene->view_settings, &scene->display_settings,
                                          rxmin, rymin, rxmin + xmax, rymin + ymax);
 }
 
index 55df1ca..3217aca 100644 (file)
@@ -63,6 +63,7 @@
 #include "RE_pipeline.h"
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -181,7 +182,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                }
 
                if ((scene->r.mode & R_OSA) == 0) { 
-                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE);
+                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE, FALSE);
                        GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, rr->rectf);
                }
                else {
@@ -195,7 +196,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                        BLI_jitter_init(jit_ofs[0], scene->r.osa);
 
                        /* first sample buffer, also initializes 'rv3d->persmat' */
-                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE);
+                       ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, TRUE, FALSE);
                        GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_buffer);
 
                        /* skip the first sample */
@@ -205,7 +206,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
                                                    (jit_ofs[j][0] * 2.0f) / sizex,
                                                    (jit_ofs[j][1] * 2.0f) / sizey);
 
-                               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, TRUE);
+                               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, TRUE, FALSE);
                                GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_tmp);
                                add_vn_vn(accum_buffer, accum_tmp, sizex * sizey * sizeof(float));
                        }
@@ -221,7 +222,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
        else {
                /* shouldnt suddenly give errors mid-render but possible */
                char err_out[256] = "unknown";
-               ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rectfloat, OB_SOLID, TRUE, err_out);
+               ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rectfloat, OB_SOLID, TRUE, FALSE, err_out);
                camera = scene->camera;
 
                if (ibuf_view) {
@@ -241,18 +242,14 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
        /* note on color management:
         *
         * OpenGL renders into sRGB colors, but render buffers are expected to be
-        * linear if color management is enabled. So we convert to linear here, so
-        * the conversion back to bytes using the color management flag can make it
-        * sRGB again, and so that e.g. openexr saving also saves the correct linear
-        * float buffer. */
+        * linear So we convert to linear here, so the conversion back to bytes can make it
+        * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
+        * correct linear float buffer.
+        */
 
-       if (oglrender->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
-               int predivide = 0; /* no alpha */
-
-               IMB_buffer_float_from_float(rr->rectf, rr->rectf,
-                                           4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, predivide,
-                                           oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
-       }
+       IMB_buffer_float_from_float(rr->rectf, rr->rectf,
+                                   4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, FALSE,
+                                   oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
 
        RE_ReleaseResult(oglrender->re);
 
@@ -536,12 +533,28 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op)
        ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
 
        if (ibuf) {
+               int needs_free = FALSE;
+
+               if (is_movie || !BKE_imtype_supports_float(scene->r.im_format.imtype)) {
+                       ImBuf *colormanage_ibuf = IMB_dupImBuf(ibuf);
+
+                       IMB_display_buffer_to_imbuf_rect(colormanage_ibuf, &scene->view_settings, &scene->display_settings);
+                       imb_freerectfloatImBuf(colormanage_ibuf);
+
+                       // IMB_freeImBuf(ibuf); /* owned by the image */
+                       ibuf = colormanage_ibuf;
+                       needs_free = TRUE;
+               }
+
                /* color -> grayscale */
                /* editing directly would alter the render view */
                if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
-                       ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
+                        ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
                        IMB_color_to_bw(ibuf_bw);
-                       // IMB_freeImBuf(ibuf); /* owned by the image */
+
+                       if (needs_free)
+                               IMB_freeImBuf(ibuf);
+
                        ibuf = ibuf_bw;
                }
                else {
@@ -551,6 +564,13 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op)
                        ibuf_cpy->rect = ibuf->rect;
                        ibuf_cpy->rect_float = ibuf->rect_float;
                        ibuf_cpy->zbuf_float = ibuf->zbuf_float;
+
+                       if (needs_free) {
+                               ibuf_cpy->mall = ibuf->mall;
+                               ibuf->mall = 0;
+                               IMB_freeImBuf(ibuf);
+                       }
+
                        ibuf = ibuf_cpy;
                }
 
index 068a7aa..38117aa 100644 (file)
@@ -64,6 +64,7 @@
 
 #include "BKE_brush.h"
 #include "BKE_context.h"
+#include "BKE_colortools.h"
 #include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_idprop.h"
 #include "BKE_material.h"
 #include "BKE_node.h"
 #include "BKE_object.h"
+#include "BKE_scene.h"
 #include "BKE_texture.h"
 #include "BKE_world.h"
 
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -254,6 +257,10 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
                }
                
                sce->r.color_mgt_flag = scene->r.color_mgt_flag;
+               BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings);
+
+               BKE_color_managed_view_settings_free(&sce->view_settings);
+               BKE_color_managed_view_settings_copy(&sce->view_settings, &scene->view_settings);
                
                /* prevent overhead for small renders and icons (32) */
                if (id && sp->sizex < 40)
@@ -263,7 +270,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
                
                /* exception: don't color manage texture previews or icons */
                if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE)
-                       sce->r.color_mgt_flag &= ~R_COLOR_MANAGEMENT;
+                       BKE_scene_disable_color_management(sce);
                
                if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO)
                        sce->r.alphamode = R_ALPHAPREMUL;
@@ -481,7 +488,7 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
        if (id && GS(id->name) != ID_TE) {
                /* exception: don't color manage texture previews - show the raw values */
                if (sce) {
-                       do_gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT;
+                       do_gamma_correct = TRUE;
                        do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE;
                }
        }
@@ -514,15 +521,25 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
                                /* temporary conversion to byte for drawing */
                                float fx = rect->xmin + offx;
                                float fy = rect->ymin;
-                               int profile_from = (do_gamma_correct) ? IB_PROFILE_LINEAR_RGB : IB_PROFILE_SRGB;
                                int dither = 0;
                                unsigned char *rect_byte;
 
                                rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
 
-                               IMB_buffer_byte_from_float(rect_byte, rres.rectf,
-                                                          4, dither, IB_PROFILE_SRGB, profile_from, do_predivide,
-                                                          rres.rectx, rres.recty, rres.rectx, rres.rectx);
+                               if (do_gamma_correct) {
+                                       IMB_display_buffer_transform_apply(rect_byte, rres.rectf, rres.rectx, rres.recty, 4,
+                                                                          &sce->view_settings, &sce->display_settings, do_predivide);
+
+                               }
+                               else {
+                                       /* OCIO_TODO: currently seems an exception for textures,
+                                        *            but is it indeed expected behavior, or textures should be
+                                        *            color managed as well?
+                                        */
+                                       IMB_buffer_byte_from_float(rect_byte, rres.rectf,
+                                                                  4, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, do_predivide,
+                                                                  rres.rectx, rres.recty, rres.rectx, rres.rectx);
+                               }
 
                                glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
 
index 9fc60ff..adb1829 100644 (file)
 #define IMAPAINT_TILE_SIZE          (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)  (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
 
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
+static void imapaint_image_update(Scene *scene, SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
 
 
 typedef struct ImagePaintState {
@@ -512,7 +512,7 @@ static void image_undo_restore(bContext *C, ListBase *lb)
                        ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
                if (ibuf->mipmap[0])
                        ibuf->userflags |= IB_MIPMAP_INVALID;  /* force mipmap recreatiom */
-
+               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
        }
 
        IMB_freeImBuf(tmpibuf);
@@ -3595,7 +3595,7 @@ static int project_image_refresh_tagged(ProjPaintState *ps)
                                pr = &(projIma->partRedrawRect[i]);
                                if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
                                        imapaintpartial = *pr;
-                                       imapaint_image_update(NULL, projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/
+                                       imapaint_image_update(NULL, NULL, projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/
                                        redraw = 1;
                                }
                        }
@@ -4224,13 +4224,17 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
                IMB_freeImBuf(tmpibuf);
 }
 
-static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
+static void imapaint_image_update(Scene *scene, SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
 {
-       if (ibuf->rect_float) {
-               IMB_partial_display_buffer_update(ibuf, ibuf->rect_float, ibuf->x, 0, 0,
+       if (scene) {
+               IMB_partial_display_buffer_update(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect, ibuf->x, 0, 0,
+                                                 &scene->view_settings, &scene->display_settings,
                                                  imapaintpartial.x1, imapaintpartial.y1,
                                                  imapaintpartial.x2, imapaintpartial.y2);
        }
+       else {
+               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+       }
        
        if (ibuf->mipmap[0])
                ibuf->userflags |= IB_MIPMAP_INVALID;
@@ -4592,7 +4596,7 @@ static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter,
 
        if (BKE_brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, ibuf->profile == IB_PROFILE_LINEAR_RGB)) {
                if (update)
-                       imapaint_image_update(s->sima, image, ibuf, texpaint);
+                       imapaint_image_update(s->scene, s->sima, image, ibuf, texpaint);
                return 1;
        }
        else return 0;
@@ -5867,7 +5871,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
        if (w > maxsize) w = maxsize;
        if (h > maxsize) h = maxsize;
 
-       ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, err_out);
+       ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, FALSE, err_out);
        if (!ibuf) {
                /* Mostly happens when OpenGL offscreen buffer was failed to create, */
                /* but could be other reasons. Should be handled in the future. nazgul */
index 90c6a5e..0b937e3 100644 (file)
@@ -193,6 +193,7 @@ void image_preview_event(int event)
        }
        
        if (exec && G.scene->nodetree) {
+               Scene *scene = G.scene;
                /* should work when no node editor in screen..., so we execute right away */
                
                ntreeCompositTagGenerators(G.scene->nodetree);
@@ -203,7 +204,7 @@ void image_preview_event(int event)
                
                BIF_store_spare();
                
-               ntreeCompositExecTree(G.scene->nodetree, &G.scene->r, 1);   /* 1 is do_previews */
+               ntreeCompositExecTree(scene->nodetree, &scene->r, 1, &scene->view_settings, &scene->display_settings);   /* 1 is do_previews */
                
                G.scene->nodetree->timecursor = NULL;
                G.scene->nodetree->test_break = NULL;
@@ -689,13 +690,10 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
                                }
                        }
 
-                       if (ima->source != IMA_SRC_GENERATED) {
-                               /* OCIO_TODO: color space transformation for byte images is not implemented yet */
-                               if (ibuf && ibuf->rect_float) {
-                                       col = uiLayoutColumn(layout, FALSE);
-                                       uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings");
-                               }
+                       col = uiLayoutColumn(layout, FALSE);
+                       uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings");
 
+                       if (ima->source != IMA_SRC_GENERATED) {
                                if (compact == 0) { /* background image view doesnt need these */
                                        uiItemS(layout);
 
index 5129212..7603ba6 100644 (file)
@@ -195,7 +195,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int channel
                if (color_manage && channels == 4) {
                        float pixel[4];
 
-                       IMB_display_buffer_pixel(pixel, fp,  &scene->view_settings, &scene->display_settings);
+                       IMB_colormanagement_pixel_to_display_space_v4(pixel, fp,  &scene->view_settings, &scene->display_settings);
 
                        BLI_snprintf(str, sizeof(str), "  |  CM  R:%-.4f  G:%-.4f  B:%-.4f", pixel[0], pixel[1], pixel[2]);
                        BLF_position(blf_mono_font, dx, 6, 0);
@@ -245,7 +245,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int channel
        }
 
        if (color_manage) {
-               IMB_display_buffer_pixel(finalcol, col,  &scene->view_settings, &scene->display_settings);
+               IMB_colormanagement_pixel_to_display_space_v4(finalcol, col,  &scene->view_settings, &scene->display_settings);
        }
        else {
                copy_v4_v4(finalcol, col);
index 05b5d5b..f9ab458 100644 (file)
@@ -1649,8 +1649,10 @@ static int image_new_exec(bContext *C, wmOperator *op)
        RNA_float_get_array(op->ptr, "color", color);
        alpha = RNA_boolean_get(op->ptr, "alpha");
        
-       if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
+       if (!floatbuf) {
+               /* OCIO_TODO: perhaps we need to convert to display space, not just to sRGB */
                linearrgb_to_srgb_v3_v3(color, color);
+       }
 
        if (!alpha)
                color[3] = 1.0f;
@@ -2263,7 +2265,7 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
        hist->co[1][0] = x2f;
        hist->co[1][1] = y2f;
 
-       BKE_histogram_update_sample_line(hist, ibuf, (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) != 0);
+       BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
        
        /* reset y zoom */
        hist->ymax = 1.0f;
@@ -2358,7 +2360,8 @@ static int image_record_composite_apply(bContext *C, wmOperator *op)
        
        BKE_image_all_free_anim_ibufs(scene->r.cfra);
        ntreeCompositTagAnimated(scene->nodetree);
-       ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra);  /* 1 is no previews */
+       ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra,
+                             &scene->view_settings, &scene->display_settings);  /* 1 is no previews */
 
        ED_area_tag_redraw(CTX_wm_area(C));
        
index 970f9d6..d9b9257 100644 (file)
@@ -770,9 +770,9 @@ static void image_scope_area_draw(const bContext *C, ARegion *ar)
        ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
        if (ibuf) {
                if (!sima->scopes.ok) {
-                       BKE_histogram_update_sample_line(&sima->sample_line_hist, ibuf, scene->r.color_mgt_flag & R_COLOR_MANAGEMENT);
+                       BKE_histogram_update_sample_line(&sima->sample_line_hist, ibuf, &scene->view_settings, &scene->display_settings);
                }
-               scopes_update(&sima->scopes, ibuf, scene->r.color_mgt_flag & R_COLOR_MANAGEMENT);
+               scopes_update(&sima->scopes, ibuf, &scene->view_settings, &scene->display_settings);
        }
        ED_space_image_release_buffer(sima, lock);
        
index 9e04bd3..cc386da 100644 (file)
@@ -148,8 +148,9 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
 {
        CompoJob *cj = cjv;
        bNodeTree *ntree = cj->localtree;
+       Scene *scene = cj->scene;
 
-       if (cj->scene->use_nodes == FALSE)
+       if (scene->use_nodes == FALSE)
                return;
        
        cj->stop = stop;
@@ -165,7 +166,7 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
        
        // XXX BIF_store_spare();
        
-       ntreeCompositExecTree(ntree, &cj->scene->r, 0, 1);  /* 1 is do_previews */
+       ntreeCompositExecTree(ntree, &cj->scene->r, 0, 1, &scene->view_settings, &scene->display_settings);  /* 1 is do_previews */
 
        ntree->test_break = NULL;
        ntree->stats_draw = NULL;
index bb82428..af9ef34 100644 (file)
@@ -146,7 +146,7 @@ static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                        info->colfp = info->colf;
 
                        /* sequencer's image buffers are in non-linear space, need to make them linear */
-                       IMB_colormanagement_pixel_from_sequencer_space(info->colf);
+                       BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->colf);
 
                        info->color_manage = TRUE;
                }
index da93e07..2e54273 100644 (file)
@@ -372,7 +372,15 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
 
        Gtexdraw.ob = ob;
        Gtexdraw.is_tex = is_tex;
-       Gtexdraw.color_profile = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
+
+       /* OCIO_TODO: for now assume OpenGL is always doing color management and working in sRGB space
+        *            supporting for real display conversion could be nice here, but it's a bit challenging
+        *            since all the shaders should be aware of such a transform
+        *            perhaps this flag could be completely removed before release in separated commit and
+        *            be re-implemented if real display transform would be needed
+        */
+       Gtexdraw.color_profile = TRUE;
+
        memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
        set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
        glShadeModel(GL_SMOOTH);
index 3f8a69f..5fbf197 100644 (file)
@@ -69,6 +69,7 @@
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -2375,7 +2376,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
                mult_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
                invert_m4_m4(rv3d.persinv, rv3d.viewinv);
 
-               ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, FALSE);
+               ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, FALSE, FALSE);
                GPU_lamp_shadow_buffer_unbind(shadow->lamp);
                
                v3d->drawtype = drawtype;
@@ -2514,7 +2515,7 @@ static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar,
 
 void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
                               int winx, int winy, float viewmat[][4], float winmat[][4],
-                              int do_bgpic)
+                              int do_bgpic, int colormanage_background)
 {
        RegionView3D *rv3d = ar->regiondata;
        Base *base;
@@ -2553,10 +2554,25 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
        /* set background color, fallback on the view background color
         * (if active clip is set but frame is failed to load fallback to horizon color as background) */
        if (scene->world) {
-               if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
+               /* NOTE: currently OpenGL is supposed to always work in sRGB space and do not
+                *       apply any tonemaps since it's really tricky to support for all features (GLSL, textures, etc)
+                *       but due to compatibility issues background is being affected display transform, so we can
+                *       emulate behavior of disabled colro management
+                *       but this function is also used for sequencer's scene strips which shouldn't be affected by
+                *       tonemaps now and should be purely sRGB, that's why we've got this colormanage_background
+                *       we can drop this flag in cost of some compatibility loss -- background wouldn't be
+                *       color managed in 3d viewport
+                *       same goes to opengl rendering, where color profile should be applied as very final step
+                */
+
+               if (colormanage_background) {
+                       IMB_colormanagement_pixel_to_display_space_v3(backcol, &scene->world->horr, &scene->view_settings,
+                                                                     &scene->display_settings);
+               }
+               else {
                        linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr);
-               else
-                       copy_v3_v3(backcol, &scene->world->horr);
+               }
+
                glClearColor(backcol[0], backcol[1], backcol[2], 0.0);
        }
        else {
@@ -2661,7 +2677,8 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
 
 /* utility func for ED_view3d_draw_offscreen */
 ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
-                                      int sizex, int sizey, unsigned int flag, int draw_background, char err_out[256])
+                                      int sizex, int sizey, unsigned int flag, int draw_background,
+                                      int colormanage_background, char err_out[256])
 {
        RegionView3D *rv3d = ar->regiondata;
        ImBuf *ibuf;
@@ -2686,10 +2703,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
                BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
                BKE_camera_params_compute_matrix(&params);
 
-               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background);
+               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background, colormanage_background);
        }
        else {
-               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background);
+               ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background, colormanage_background);
        }
 
        /* read in pixels & stamp */
@@ -2714,7 +2731,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar,
 
 /* creates own 3d views, used by the sequencer */
 ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height,
-                                             unsigned int flag, int drawtype, int draw_background, char err_out[256])
+                                             unsigned int flag, int drawtype, int draw_background,
+                                             int colormanage_background, char err_out[256])
 {
        View3D v3d = {NULL};
        ARegion ar = {NULL};
@@ -2753,7 +2771,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
        mult_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
        invert_m4_m4(rv3d.persinv, rv3d.viewinv);
 
-       return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag, draw_background, err_out);
+       return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
+                                             draw_background, colormanage_background, err_out);
 
        // seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
 }
@@ -2936,10 +2955,9 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const
 
        /* clear background */
        if ((v3d->flag2 & V3D_RENDER_OVERRIDE) && scene->world) {
-               if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
-                       linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr);
-               else
-                       copy_v3_v3(backcol, &scene->world->horr);
+               IMB_colormanagement_pixel_to_display_space_v3(backcol, &scene->world->horr, &scene->view_settings,
+                                                             &scene->display_settings);
+
                glClearColor(backcol[0], backcol[1], backcol[2], 0.0);
        }
        else
index 4314a78..95e2889 100644 (file)
@@ -1197,7 +1197,12 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
        GPUMaterial *gpumat;
        GPUBlendMode alphablend;
        int a;
-       int gamma = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
+
+       /* OCIO_TODO: assume color management is always enabled. could be nice to support real display transform here,
+        *            but that's not so important and could be done later
+        */
+       int gamma = TRUE;
+
        int new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
        
        /* initialize state */
index 61be405..dd92b56 100644 (file)
@@ -389,8 +389,12 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
 
 int GPU_material_do_color_management(GPUMaterial *mat)
 {
-       return ((mat->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) &&
-          !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT)));
+       /* OCIO_TODO: for now assume scene always does color management. probably could be
+        *            improved in the future to support real display transform
+        *            also probably we'll need to get rid ofgame engine's color management flag
+        */
+
+       return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT));
 }
 
 static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
index 2df67b6..0dc8264 100644 (file)
@@ -37,6 +37,7 @@ struct bContext;
 struct ColorManagedColorspaceSettings;
 struct ColorManagedDisplaySettings;
 struct ColorManagedViewSettings;
+struct ColormanageProcessor;
 struct EnumPropertyItem;
 struct ImBuf;
 struct Main;
@@ -45,6 +46,9 @@ struct PartialBufferUpdateContext;
 struct wmWindow;
 struct Scene;
 
+struct ColorSpace;
+struct ColorManagedDisplay;
+
 /* ** Initialization / De-initialization ** */
 
 void IMB_colormanagement_init(void);
@@ -57,17 +61,39 @@ void IMB_colormanagement_check_file_config(struct Main *bmain);
 void IMB_colormanagement_validate_settings(struct ColorManagedDisplaySettings *display_settings,
                                            struct ColorManagedViewSettings *view_settings);
 
+const char *IMB_colormanagement_role_colorspace_name_get(int role);
+void IMB_colormanagement_imbuf_float_from_rect(struct ImBuf *ibuf);
+
 /* ** Color space transformation functions ** */
-void IMB_colormanagement_colorspace_transform(float *buffer, int width, int height, int channels,
-                                              const char *from_colorspace, const char *to_colorspace,
-                                              int predivide);
+void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
+                                   const char *from_colorspace, const char *to_colorspace, int predivide);
+void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
+                                            const char *from_colorspace, const char *to_colorspace, int predivide);
+void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace);
+
+void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace);
+void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], struct ColorSpace *colorspace);
+
+void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide);
 
-void IMB_colormanagement_pixel_to_role(float pixel[4], int role);
-void IMB_colormanagement_pixel_from_role(float pixel[4], int role);
+void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], struct ColorManagedDisplay *display);
+void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], struct ColorManagedDisplay *display);
+
+void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4],  const struct ColorManagedViewSettings *view_settings,
+                                                   const struct ColorManagedDisplaySettings *display_settings);
+
+void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float pixel[3],  const struct ColorManagedViewSettings *view_settings,
+                                                   const struct ColorManagedDisplaySettings *display_settings);
+
+void IMB_colormanagement_pixel_to_role_v4(float pixel[4], int role);
+void IMB_colormanagement_pixel_from_role_v4(float pixel[4], int role);
 
 void IMB_colormanagement_imbuf_to_role(struct ImBuf *ibuf, int role);
 void IMB_colormanagement_imbuf_from_role(struct ImBuf *ibuf, int role);
 
+void IMB_colormanagement_imbuf_assign_spaces(struct ImBuf *ibuf, struct ColorManagedColorspaceSettings *colorspace_settings);
+void IMB_colormanagement_imbuf_assign_float_space(struct ImBuf *ibuf, struct ColorManagedColorspaceSettings *colorspace_settings);
+
 void IMB_colormanagement_imbuf_make_scene_linear(struct ImBuf *ibuf, struct ColorManagedColorspaceSettings *colorspace_settings);
 
 void IMB_colormanagement_imbuf_make_display_space(struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings,
@@ -75,26 +101,24 @@ void IMB_colormanagement_imbuf_make_display_space(struct ImBuf *ibuf, const stru
 
 /* ** Public display buffers interfaces ** */
 
-void IMB_colormanage_cache_free(struct ImBuf *ibuf);
-
 unsigned char *IMB_display_buffer_acquire(struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings,
                                           const struct ColorManagedDisplaySettings *display_settings, void **cache_handle);
 unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C, struct ImBuf *ibuf, void **cache_handle);
 
-void IMB_display_buffer_pixel(float result[4], const float pixel[4],  const struct ColorManagedViewSettings *view_settings,
-                              const struct ColorManagedDisplaySettings *display_settings);
-
 void IMB_display_buffer_to_imbuf_rect(struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings,
                                       const struct ColorManagedDisplaySettings *display_settings);
 
-void IMB_display_buffer_release(void *cache_handle);
+void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height,
+                                        int channels, const struct ColorManagedViewSettings *view_settings,
+                                        const struct ColorManagedDisplaySettings *display_settings, int predivide);
 
-void IMB_display_buffer_invalidate(struct ImBuf *ibuf);
+void IMB_display_buffer_release(void *cache_handle);
 
 /* ** Display funcrions ** */
 int IMB_colormanagement_display_get_named_index(const char *name);
 const char *IMB_colormanagement_display_get_indexed_name(int index);
 const char *IMB_colormanagement_display_get_default_name(void);
+struct ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name);
 
 /* ** View funcrions ** */
 int IMB_colormanagement_view_get_named_index(const char *name);
@@ -103,6 +127,7 @@ const char *IMB_colormanagement_view_get_indexed_name(int index);
 /* ** Color space functions ** */
 int IMB_colormanagement_colorspace_get_named_index(const char *name);
 const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
+const char *IMB_colormanagement_view_get_default_name(const char *display_name);
 
 /* ** RNA helper functions ** */
 void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
@@ -110,26 +135,29 @@ void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items, int *to
 void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
 
 /* ** Tile-based buffer management ** */
-void IMB_partial_display_buffer_update(struct ImBuf *ibuf, const float *linear_buffer,
-                                       int stride, int offset_x, int offset_y,
+void IMB_partial_display_buffer_update(struct ImBuf *ibuf, const float *linear_buffer, const unsigned char *buffer_byte,
+                                       int stride, int offset_x, int offset_y, const struct ColorManagedViewSettings *view_settings,
+                                       const struct ColorManagedDisplaySettings *display_settings,
                                        int xmin, int ymin, int xmax, int ymax);
 
-/* ** Area-specific functions ** */
-
-/* Sequencer */
-
-void IMB_colormanagement_imbuf_to_sequencer_space(struct ImBuf *ibuf, int make_float);
-void IMB_colormanagement_imbuf_from_sequencer_space(struct ImBuf *ibuf);
-
-void IMB_colormanagement_pixel_from_sequencer_space(float pixel[4]);
-
+/* ** Pixel processor functions ** */
+struct ColormanageProcessor *IMB_colormanagement_display_processor_new(const struct ColorManagedViewSettings *view_settings,
+                                                                       const struct ColorManagedDisplaySettings *display_settings);
+struct ColormanageProcessor *IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace);
+void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4]);
+void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3]);
+void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height,
+                                         int channels, int predivide);
+void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
 
 /* Roles */
 enum {
        COLOR_ROLE_SCENE_LINEAR = 0,
        COLOR_ROLE_COLOR_PICKING,
        COLOR_ROLE_TEXTURE_PAINTING,
-       COLOR_ROLE_SEQUENCER,
+       COLOR_ROLE_DEFAULT_SEQUENCER,
+       COLOR_ROLE_DEFAULT_BYTE,
+       COLOR_ROLE_DEFAULT_FLOAT,
 };
 
-#endif // IMB_COLORMANAGEMENT_H
+#endif  /* IMB_COLORMANAGEMENT_H */
index 9466be1..428bd40 100644 (file)
@@ -128,8 +128,10 @@ typedef struct ImBuf {
        unsigned int   encodedbuffersize; /* Size of encodedbuffer */
 
        /* color management */
-       int colormanage_flags;
-       unsigned int *display_buffer_flags;  /* array of per-display display buffers dirty flags */
+       int colormanage_flags;                       /* color management flags field */
+       struct ColorSpace *rect_colorspace;          /* color space of byte buffer */
+       struct ColorSpace *float_colorspace;          /* color space of float buffer, used by sequencer only */
+       unsigned int *display_buffer_flags;          /* array of per-display display buffers dirty flags */
        struct ColormanageCache *colormanage_cache;  /* cache used by color management */
 
        /* information for compressed textures */
@@ -141,10 +143,11 @@ typedef struct ImBuf {
  * \brief userflags: Flags used internally by blender for imagebuffers
  */
 
-#define IB_BITMAPFONT          (1 << 0)        /* this image is a font */
-#define IB_BITMAPDIRTY         (1 << 1)        /* image needs to be saved is not the same as filename */
-#define IB_MIPMAP_INVALID      (1 << 2)        /* image mipmaps are invalid, need recreate */
-#define IB_RECT_INVALID                (1 << 3)    /* float buffer changed, needs recreation of byte rect */
+#define IB_BITMAPFONT                  (1 << 0)        /* this image is a font */
+#define IB_BITMAPDIRTY                 (1 << 1)        /* image needs to be saved is not the same as filename */
+#define IB_MIPMAP_INVALID              (1 << 2)        /* image mipmaps are invalid, need recreate */
+#define IB_RECT_INVALID                        (1 << 3)        /* float buffer changed, needs recreation of byte rect */
+#define IB_DISPLAY_BUFFER_INVALID      (1 << 4)        /* either float or byte buffer changed, need to re-calculate display buffers */
 
 /**
  * \name Imbuf Component flags
index 628a96d..8dd02b9 100644 (file)
 
 #define BCM_CONFIG_FILE "config.ocio"
 
+struct ConstProcessorRcPtr;
+
 typedef struct ColorSpace {
        struct ColorSpace *next, *prev;
        int index;
        char name[64];
        char description[64];
+
+       struct ConstProcessorRcPtr *to_scene_linear;
+       struct ConstProcessorRcPtr *from_scene_linear;
 } ColorSpace;
 
 typedef struct ColorManagedDisplay {
@@ -47,6 +52,9 @@ typedef struct ColorManagedDisplay {
        int index;
        char name[64];
        ListBase views;
+
+       struct ConstProcessorRcPtr *to_scene_linear;
+       struct ConstProcessorRcPtr *from_scene_linear;
 } ColorManagedDisplay;
 
 typedef struct ColorManagedView {
@@ -55,11 +63,14 @@ typedef struct ColorManagedView {
        char name[64];
 } ColorManagedView;
 
+void colormanage_cache_free(struct ImBuf *ibuf);
+
 struct ColorManagedDisplay *colormanage_display_get_default(void);
 struct ColorManagedDisplay *colormanage_display_add(const char *name);
 struct ColorManagedDisplay *colormanage_display_get_named(const char *name);
 struct ColorManagedDisplay *colormanage_display_get_indexed(int index);
 
+const char *colormanage_view_get_default_name(const ColorManagedDisplay *display);
 struct ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display);
 struct ColorManagedView *colormanage_view_add(const char *name);
 struct ColorManagedView *colormanage_view_get_indexed(int index);
@@ -69,4 +80,4 @@ struct ColorSpace *colormanage_colorspace_add(const char *name, const char *desc
 struct ColorSpace *colormanage_colorspace_get_named(const char *name);
 struct ColorSpace *colormanage_colorspace_get_indexed(int index);
 
-#endif // IMB_COLORMANAGEMENT_INTERN_H
+#endif  /* IMB_COLORMANAGEMENT_INTERN_H */
index bee4758..32c14e3 100644 (file)
@@ -41,7 +41,7 @@
 #include "IMB_allocimbuf.h"
 #include "IMB_filetype.h"
 #include "IMB_metadata.h"
-#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
 
 #include "imbuf.h"
 
@@ -163,7 +163,7 @@ void IMB_freeImBuf(ImBuf *ibuf)
                        IMB_freezbuffloatImBuf(ibuf);
                        freeencodedbufferImBuf(ibuf);
                        IMB_metadata_free(ibuf);
-                       IMB_colormanage_cache_free(ibuf);
+                       colormanage_cache_free(ibuf);
 
                        if (ibuf->dds_data.data != NULL) {
                                free(ibuf->dds_data.data); /* dds_data.data is allocated by DirectDrawSurface::readData(), so don't use MEM_freeN! */
@@ -358,7 +358,7 @@ ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, uchar planes, unsigned int
                ibuf->ftype = TGA;
                ibuf->channels = 4;  /* float option, is set to other values when buffers get assigned */
                ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254; /* IMB_DPI_DEFAULT -> pixels-per-meter */
-               
+
                if (flags & IB_rect) {
                        if (imb_addrectImBuf(ibuf) == FALSE) {
                                IMB_freeImBuf(ibuf);
index f394f84..8ce8105 100644 (file)
@@ -74,15 +74,16 @@ typedef struct ConstProcessorRcPtr {
 
 /*********************** Global declarations *************************/
 
-/* define this to allow byte buffers be color managed */
-#undef COLORMANAGE_BYTE_BUFFER
+#define MAX_COLORSPACE_NAME 64
 
 /* ** list of all supported color spaces, displays and views */
 #ifdef WITH_OCIO
-static char global_role_scene_linear[64];
-static char global_role_color_picking[64];
-static char global_role_texture_painting[64];
-static char global_role_sequencer[64];
+static char global_role_scene_linear[MAX_COLORSPACE_NAME];
+static char global_role_color_picking[MAX_COLORSPACE_NAME];
+static char global_role_texture_painting[MAX_COLORSPACE_NAME];
+static char global_role_default_byte[MAX_COLORSPACE_NAME];
+static char global_role_default_float[MAX_COLORSPACE_NAME];
+static char global_role_default_sequencer[MAX_COLORSPACE_NAME];
 #endif
 
 static ListBase global_colorspaces = {NULL};
@@ -93,6 +94,19 @@ static int global_tot_colorspace = 0;
 static int global_tot_display = 0;
 static int global_tot_view = 0;
 
+typedef struct ColormanageProcessor {
+       ConstProcessorRcPtr *processor;
+       CurveMapping *curve_mapping;
+
+#ifndef WITH_OCIO
+       /* this callback is only used in cases when Blender was build without OCIO
+        * and aimed to preserve compatibility with previous Blender versions
+        */
+       void (*display_transform_cb_v3) (float result[3], const float pixel[3]);
+       void (*display_transform_predivide_cb_v4) (float result[4], const float pixel[4]);
+#endif
+} ColormanageProcessor;
+
 /*********************** Color managed cache *************************/
 
 /* Cache Implementation Notes
@@ -237,9 +251,8 @@ static int colormanage_hashcmp(const void *av, const void *bv)
 
 static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
 {
-       if (!ibuf->colormanage_cache) {
+       if (!ibuf->colormanage_cache)
                ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
-       }
 
        if (!ibuf->colormanage_cache->moviecache) {
                struct MovieCache *moviecache;
@@ -255,9 +268,8 @@ static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
 
 static void colormanage_cachedata_set(ImBuf *ibuf, ColormnaageCacheData *data)
 {
-       if (!ibuf->colormanage_cache) {
+       if (!ibuf->colormanage_cache)
                ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
-       }
 
        ibuf->colormanage_cache->data = data;
 }
@@ -296,7 +308,7 @@ static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf, ColormanageCacheKey *key,
        struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
 
        if (!moviecache) {
-               /* if there's no moviecache it means no color management was applied before */
+               /* if there's no moviecache it means no color management was applied on given image buffer before */
 
                return NULL;
        }
@@ -341,7 +353,7 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
                 * in cache separately. buffer which were used only different exposure/gamma
                 * are re-suing the same cached buffer
                 *
-                * check here which exposure/gamma was used for cached buffer and if they're
+                * check here which exposure/gamma/curve was used for cached buffer and if they're
                 * different from requested buffer should be re-generated
                 */
                cache_data = colormanage_cachedata_get(cache_ibuf);
@@ -406,30 +418,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
 
        IMB_moviecache_put(moviecache, &key, cache_ibuf);
 }
-
-static unsigned char *colormanage_cache_get_cache_data(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings,
-                                                       const ColormanageCacheDisplaySettings *display_settings,
-                                                       void **cache_handle, float *exposure, float *gamma)
-{
-       ColormanageCacheKey key;
-       ColormnaageCacheData *cache_data;
-       ImBuf *cache_ibuf;
-
-       colormanage_settings_to_key(&key, view_settings, display_settings);
-
-       cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
-
-       if (cache_ibuf) {
-               cache_data = colormanage_cachedata_get(cache_ibuf);
-
-               *exposure = cache_data->exposure;
-               *gamma = cache_data->gamma;
-
-               return (unsigned char *) cache_ibuf->rect;
-       }
-
-       return NULL;
-}
 #endif
 
 static void colormanage_cache_handle_release(void *cache_handle)
@@ -442,8 +430,7 @@ static void colormanage_cache_handle_release(void *cache_handle)
 /*********************** Initialization / De-initialization *************************/
 
 #ifdef WITH_OCIO
-static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char *colorspace_name,
-                                                  int max_colorspace_name, const char *role, const char *role_name)
+static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char *colorspace_name, const char *role)
 {
        ConstColorSpaceRcPtr *ociocs;
 
@@ -452,11 +439,12 @@ static void colormanage_role_color_space_name_get(ConstConfigRcPtr *config, char
        if (ociocs) {
                const char *name = OCIO_colorSpaceGetName(ociocs);
 
-               BLI_strncpy(colorspace_name, name, max_colorspace_name);
+               /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
+               BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
                OCIO_colorSpaceRelease(ociocs);
        }
        else {
-               printf("Blender color management: Error could not find %s role.\n", role_name);
+               printf("Blender color management: Error could not find role %s role.\n", role);
        }
 }
 
@@ -466,17 +454,12 @@ static void colormanage_load_config(ConstConfigRcPtr *config)
        const char *name;
 
        /* get roles */
-       colormanage_role_color_space_name_get(config, global_role_scene_linear, sizeof(global_role_scene_linear),
-                                             OCIO_ROLE_SCENE_LINEAR, "scene linear");
-
-       colormanage_role_color_space_name_get(config, global_role_color_picking, sizeof(global_role_color_picking),
-                                             OCIO_ROLE_COLOR_PICKING, "color picking");
-
-       colormanage_role_color_space_name_get(config, global_role_texture_painting, sizeof(global_role_texture_painting),
-                                             OCIO_ROLE_TEXTURE_PAINT, "texture painting");
-
-       colormanage_role_color_space_name_get(config, global_role_sequencer, sizeof(global_role_sequencer),
-                                             OCIO_ROLE_SEQUENCER, "sequencer");
+       colormanage_role_color_space_name_get(config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR);
+       colormanage_role_color_space_name_get(config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING);
+       colormanage_role_color_space_name_get(config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT);
+       colormanage_role_color_space_name_get(config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER);
+       colormanage_role_color_space_name_get(config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE);
+       colormanage_role_color_space_name_get(config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT);
 
        /* load colorspaces */
        tot_colorspace = OCIO_configGetNumColorSpaces(config);
@@ -535,39 +518,46 @@ void colormanage_free_config(void)
 {
        ColorSpace *colorspace;
        ColorManagedDisplay *display;
-       ColorManagedView *view;
 
+       /* free color spaces */
        colorspace = global_colorspaces.first;
        while (colorspace) {
                ColorSpace *colorspace_next = colorspace->next;
 
+               /* free precomputer processors */
+               if (colorspace->to_scene_linear)
+                       OCIO_processorRelease((ConstProcessorRcPtr *) colorspace->to_scene_linear);
+
+               if (colorspace->from_scene_linear)
+                       OCIO_processorRelease((ConstProcessorRcPtr *) colorspace->from_scene_linear);
+
+               /* free color space itself */
                MEM_freeN(colorspace);
+
                colorspace = colorspace_next;
        }
 
+       /* free displays */
        display = global_displays.first;
        while (display) {
                ColorManagedDisplay *display_next = display->next;
-               LinkData *display_view = display->views.first;
 
-               while (display_view) {
-                       LinkData *display_view_next = display_view->next;
+               /* free precomputer processors */
+               if (display->to_scene_linear)
+                       OCIO_processorRelease((ConstProcessorRcPtr *) display->to_scene_linear);
 
-                       MEM_freeN(display_view);
-                       display_view = display_view_next;
-               }
+               if (display->from_scene_linear)
+                       OCIO_processorRelease((ConstProcessorRcPtr *) display->from_scene_linear);
+
+               /* free list of views */
+               BLI_freelistN(&display->views);
 
                MEM_freeN(display);
                display = display_next;
        }
 
-       view = global_views.first;
-       while (view) {
-               ColorManagedView *view_next = view->next;
-
-               MEM_freeN(view);
-               view = view_next;
-       }
+       /* free views */
+       BLI_freelistN(&global_views);
 }
 #endif
 
@@ -581,10 +571,10 @@ void IMB_colormanagement_init(void)
 
        ocio_env = getenv("OCIO");
 
-       if (ocio_env) {
+       if (ocio_env)
                config = OCIO_configCreateFromEnv();
-       }
-       else {
+
+       if (config == NULL) {
                configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement");
 
                if (configdir)  {
@@ -601,7 +591,6 @@ void IMB_colormanagement_init(void)
        }
 
        OCIO_configRelease(config);
-
 #endif
 
        BLI_init_srgb_conversion();
@@ -614,302 +603,657 @@ void IMB_colormanagement_exit(void)
 #endif
 }
 
-/*********************** Threaded display buffer transform routines *************************/
+/*********************** Internal functions *************************/
 
-#ifdef WITH_OCIO
-typedef struct DisplayBufferThread {
-       CurveMapping *curve_mapping;
-       void *processor;
+void colormanage_cache_free(ImBuf *ibuf)
+{
+       if (ibuf->display_buffer_flags) {
+               MEM_freeN(ibuf->display_buffer_flags);
 
-       float *buffer;
-       unsigned char *byte_buffer;
+               ibuf->display_buffer_flags = NULL;
+       }
 
-       float *display_buffer;
-       unsigned char *display_buffer_byte;
+       if (ibuf->colormanage_cache) {
+               ColormnaageCacheData *cache_data = colormanage_cachedata_get(ibuf);
+               struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
 
-       int width;
-       int start_line;
-       int tot_line;
+               if (cache_data) {
+                       MEM_freeN(cache_data);
+               }
 
-       int channels;
-       int dither;
-       int predivide;
+               if (moviecache) {
+                       IMB_moviecache_free(moviecache);
+               }
 
-       int nolinear_float;
-} DisplayBufferThread;
+               MEM_freeN(ibuf->colormanage_cache);
 
-typedef struct DisplayBufferInitData {
-       ImBuf *ibuf;
-       CurveMapping *curve_mapping;
-       void *processor;
-       float *buffer;
-       unsigned char *byte_buffer;
+               ibuf->colormanage_cache = NULL;
+       }
+}
 
-       float *display_buffer;
-       unsigned char *display_buffer_byte;
+static void display_transform_get_from_ctx(const bContext *C, ColorManagedViewSettings **view_settings_r,
+                                           ColorManagedDisplaySettings **display_settings_r)
+{
+       Scene *scene = CTX_data_scene(C);
 
-       int width;
-} DisplayBufferInitData;
+       *view_settings_r = &scene->view_settings;
+       *display_settings_r = &scene->display_settings;
+}
 
-static void display_buffer_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+#ifdef WITH_OCIO
+static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display,
+                                                            float exposure, float gamma)
 {
-       DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
-       DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v;
-       ImBuf *ibuf = init_data->ibuf;
-       CurveMapping *curve_mapping = init_data->curve_mapping;
+       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+       DisplayTransformRcPtr *dt;
+       ConstProcessorRcPtr *processor;
 
-       int predivide = ibuf->flags & IB_cm_predivide;
-       int channels = ibuf->channels;
-       int dither = ibuf->dither;
+       if (!config) {
+               /* there's no valid OCIO configuration, can't create processor */
 
-       int offset = channels * start_line * ibuf->x;
+               return NULL;
+       }
 
-       memset(handle, 0, sizeof(DisplayBufferThread));
+       dt = OCIO_createDisplayTransform();
 
-       handle->processor = init_data->processor;
+       /* assuming handling buffer was already converted to scene linear space */
+       OCIO_displayTransformSetInputColorSpaceName(dt, global_role_scene_linear);
+       OCIO_displayTransformSetView(dt, view_transform);
+       OCIO_displayTransformSetDisplay(dt, display);
 
-       if (init_data->buffer)
-               handle->buffer = init_data->buffer + offset;
+       /* fstop exposure control */
+       if (exposure != 0.0f) {
+               MatrixTransformRcPtr *mt;
+               float gain = powf(2.0f, exposure);
+               const float scale4f[] = {gain, gain, gain, gain};
+               float m44[16], offset4[4];
 
-       if (init_data->byte_buffer)
-               handle->byte_buffer = init_data->byte_buffer + offset;
+               OCIO_matrixTransformScale(m44, offset4, scale4f);
+               mt = OCIO_createMatrixTransform();
+               OCIO_matrixTransformSetValue(mt, m44, offset4);
+               OCIO_displayTransformSetLinearCC(dt, (ConstTransformRcPtr *) mt);
 
-       if (init_data->display_buffer)
-               handle->display_buffer = init_data->display_buffer + offset;
+               OCIO_matrixTransformRelease(mt);
+       }
 
-       if (init_data->display_buffer_byte)
-               handle->display_buffer_byte = init_data->display_buffer_byte + offset;
+       /* post-display gamma transform */
+       if (gamma != 1.0f) {
+               ExponentTransformRcPtr *et;
+               float exponent = 1.0f / MAX2(FLT_EPSILON, gamma);
+               const float exponent4f[] = {exponent, exponent, exponent, exponent};
 
-       handle->width = ibuf->x;
+               et = OCIO_createExponentTransform();
+               OCIO_exponentTransformSetValue(et, exponent4f);
+               OCIO_displayTransformSetDisplayCC(dt, (ConstTransformRcPtr *) et);
 
-       handle->start_line = start_line;
-       handle->tot_line = tot_line;
+               OCIO_exponentTransformRelease(et);
+       }
 
-       handle->channels = channels;
-       handle->dither = dither;
-       handle->predivide = predivide;
-       handle->curve_mapping = curve_mapping;
+       processor = OCIO_configGetProcessor(config, (ConstTransformRcPtr *) dt);
 
-       handle->nolinear_float = ibuf->colormanage_flags & IMB_COLORMANAGE_NOLINEAR_FLOAT;
+       OCIO_displayTransformRelease(dt);
+       OCIO_configRelease(config);
+
+       return processor;
 }
 
-static void display_buffer_apply_threaded(ImBuf *ibuf, float *buffer, unsigned char *byte_buffer,
-                                          float *display_buffer, unsigned char *display_buffer_byte,
-                                          CurveMapping *curve_mapping, void *processor, void *(do_thread) (void *))
+static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
+                                                                  const char *to_colorspace)
 {
-       DisplayBufferInitData init_data;
-
-       init_data.ibuf = ibuf;
-       init_data.curve_mapping = curve_mapping;
-       init_data.processor = processor;
-       init_data.buffer = buffer;
-       init_data.byte_buffer = byte_buffer;
-       init_data.display_buffer = display_buffer;
-       init_data.display_buffer_byte = display_buffer_byte;
+       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+       ConstProcessorRcPtr *processor;
 
-       IMB_processor_apply_threaded(ibuf->y, sizeof(DisplayBufferThread), &init_data,
-                                    display_buffer_init_handle, do_thread);
-}
+       if (!config) {
+               /* there's no valid OCIO configuration, can't create processor */
 
-static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
-{
-       float *linear_buffer = NULL;
+               return NULL;
+       }
 
-       int channels = handle->channels;
-       int width = handle->width;
-       int height = handle->tot_line;
+       processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
 
-       int buffer_size = channels * width * height;
+       OCIO_configRelease(config);
 
-       int predivide = handle->predivide;
+       return processor;
+}
 
-       linear_buffer = MEM_callocN(buffer_size * sizeof(float), "color conversion linear buffer");
+static ConstProcessorRcPtr *colorspace_to_scene_linear_processor(ColorSpace *colorspace)
+{
+       if (colorspace->to_scene_linear == NULL) {
+               BLI_lock_thread(LOCK_COLORMANAGE);
 
-       if (!handle->buffer) {
-               unsigned char *byte_buffer = handle->byte_buffer;
+               if (colorspace->to_scene_linear == NULL) {
+                       ConstProcessorRcPtr *to_scene_linear;
+                       to_scene_linear = create_colorspace_transform_processor(colorspace->name, global_role_scene_linear);
+                       colorspace->to_scene_linear = (struct ConstProcessorRcPtr *) to_scene_linear;
+               }
 
-               /* OCIO_TODO: for now assume byte buffers are in sRGB space,
-                *            in the future it shall use color space specified
-                *            by user
-                */
-               IMB_buffer_float_from_byte(linear_buffer, byte_buffer,
-                                          IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB,
-                                          predivide, width, height, width, width);
+               BLI_unlock_thread(LOCK_COLORMANAGE);
        }
-       else if (handle->nolinear_float) {
-               /* currently float is non-linear only in sequencer, which is working
-                * in it's own color space even to handle float buffers, so we need to ensure
-                * float buffer is in linear space before applying all the view transformations
-                */
 
-               const char *from_colorspace = global_role_sequencer;
-               const char *to_colorspace = global_role_scene_linear;
+       return (ConstProcessorRcPtr *) colorspace->to_scene_linear;
+}
 
-               memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
+static ConstProcessorRcPtr *colorspace_from_scene_linear_processor(ColorSpace *colorspace)
+{
+       if (colorspace->from_scene_linear == NULL) {
+               BLI_lock_thread(LOCK_COLORMANAGE);
 
-               IMB_colormanagement_colorspace_transform(linear_buffer, width, height, channels,
-                                                        from_colorspace, to_colorspace, predivide);
-       }
-       else {
-               /* some processors would want to modify float original buffer
-                * before converting it into display byte buffer, so we need to
-                * make sure original's ImBuf buffers wouldn't be modified by
-                * using duplicated buffer here
-                *
-                * NOTE: MEM_dupallocN can't be used because buffer could be
-                *       specified as an offset inside allocated buffer
-                */
+               if (colorspace->from_scene_linear == NULL) {
+                       ConstProcessorRcPtr *from_scene_linear;
+                       from_scene_linear = create_colorspace_transform_processor(global_role_scene_linear, colorspace->name);
+                       colorspace->from_scene_linear = (struct ConstProcessorRcPtr *) from_scene_linear;
+               }
 
-               memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
+               BLI_unlock_thread(LOCK_COLORMANAGE);
        }
 
-       return linear_buffer;
+       return (ConstProcessorRcPtr *) colorspace->from_scene_linear;
 }
 
-static void *do_display_buffer_apply_thread(void *handle_v)
+static ConstProcessorRcPtr *display_from_scene_linear_processor(ColorManagedDisplay *display)
 {
-       DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
-       CurveMapping *curve_mapping = handle->curve_mapping;
-       ConstProcessorRcPtr *processor = (ConstProcessorRcPtr *) handle->processor;
-       PackedImageDesc *img;
-       float *buffer = handle->buffer;
-       float *display_buffer = handle->display_buffer;
-       unsigned char *display_buffer_byte = handle->display_buffer_byte;
-       int channels = handle->channels;
-       int width = handle->width;
-       int height = handle->tot_line;
-       int dither = handle->dither;
-       int predivide = handle->predivide;
-
-       float *linear_buffer = display_buffer_apply_get_linear_buffer(handle);
+       if (display->from_scene_linear == NULL) {
+               BLI_lock_thread(LOCK_COLORMANAGE);
 
-       if (curve_mapping) {
-               int x, y;
+               if (display->from_scene_linear == NULL) {
+                       const char *view_name = colormanage_view_get_default_name(display);
+                       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+                       ConstProcessorRcPtr *processor = NULL;
 
-               for (y = 0; y < height; y++) {
-                       for (x = 0; x < width; x++) {
-                               float *pixel = linear_buffer + channels * (y * width + x);
+                       if (view_name && config) {
+                               const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name);
+                               processor = OCIO_configGetProcessorWithNames(config, global_role_scene_linear, view_colorspace);
 
-                               if (channels == 1) {
-                                       pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
-                               }
-                               else if (channels == 2) {
-                                       pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
-                                       pixel[1] = curvemap_evaluateF(curve_mapping->cm, pixel[1]);
-                               }
-                               else {
-                                       curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
-                               }
+                               OCIO_configRelease(config);
                        }
-               }
-       }
-
-       img = OCIO_createPackedImageDesc(linear_buffer, width, height, channels, sizeof(float),
-                                        channels * sizeof(float), channels * sizeof(float) * width);
 
-       if (predivide)
-               OCIO_processorApply_predivide(processor, img);
-       else
-               OCIO_processorApply(processor, img);
-
-       OCIO_packedImageDescRelease(img);
-
-       if (display_buffer_byte) {
-               /* do conversion */
-               IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer,
-                                          channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
-                                          predivide, width, height, width, width);
-       }
+                       display->from_scene_linear = (struct ConstProcessorRcPtr *) processor;
+               }
 
-       if (display_buffer) {
-               memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
+               BLI_unlock_thread(LOCK_COLORMANAGE);
        }
 
-       if (linear_buffer != buffer)
-               MEM_freeN(linear_buffer);
-
-       return NULL;
+       return (ConstProcessorRcPtr *) display->from_scene_linear;
 }
 
-static ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, const char *display,
-                                                            float exposure, float gamma)
+static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display)
 {
-       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
-       DisplayTransformRcPtr *dt;
-       ExponentTransformRcPtr *et;
-       MatrixTransformRcPtr *mt;
-       ConstProcessorRcPtr *processor;
+       if (display->to_scene_linear == NULL) {
+               BLI_lock_thread(LOCK_COLORMANAGE);
 
-       float exponent = 1.0f / MAX2(FLT_EPSILON, gamma);
-       const float exponent4f[] = {exponent, exponent, exponent, exponent};
+               if (display->to_scene_linear == NULL) {
+                       const char *view_name = colormanage_view_get_default_name(display);
+                       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+                       ConstProcessorRcPtr *processor = NULL;
 
-       float gain = powf(2.0f, exposure);
-       const float scale4f[] = {gain, gain, gain, gain};
-       float m44[16], offset4[4];
+                       if (view_name && config) {
+                               const char *view_colorspace = OCIO_configGetDisplayColorSpaceName(config, display->name, view_name);
+                               processor = OCIO_configGetProcessorWithNames(config, view_colorspace, global_role_scene_linear);
 
-       if (!config) {
-               /* there's no valid OCIO configuration, can't create processor */
+                               OCIO_configRelease(config);
+                       }
 
-               return NULL;
+                       display->to_scene_linear = (struct ConstProcessorRcPtr *) processor;
+               }
+
+               BLI_unlock_thread(LOCK_COLORMANAGE);
        }
 
-       dt = OCIO_createDisplayTransform();
+       return (ConstProcessorRcPtr *) display->to_scene_linear;
+}
+#endif
 
-       /* assuming handling buffer was already converted to scene linear space */
-       OCIO_displayTransformSetInputColorSpaceName(dt, global_role_scene_linear);
-       OCIO_displayTransformSetView(dt, view_transform);
-       OCIO_displayTransformSetDisplay(dt, display);
+static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
+{
+       if (channels == 1) {
+               pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
+       }
+       else if (channels == 2) {
+               pixel[0] = curvemap_evaluateF(curve_mapping->cm, pixel[0]);
+               pixel[1] = curvemap_evaluateF(curve_mapping->cm, pixel[1]);
+       }
+       else {
+               curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
+       }
+}
 
-       /* fstop exposure control */
-       OCIO_matrixTransformScale(m44, offset4, scale4f);
-       mt = OCIO_createMatrixTransform();
-       OCIO_matrixTransformSetValue(mt, m44, offset4);
-       OCIO_displayTransformSetLinearCC(dt, (ConstTransformRcPtr *) mt);
+/*********************** Generic functions *************************/
 
-       /* post-display gamma transform */
-       et = OCIO_createExponentTransform();
-       OCIO_exponentTransformSetValue(et, exponent4f);
-       OCIO_displayTransformSetDisplayCC(dt, (ConstTransformRcPtr *) et);
+#ifdef WITH_OCIO
+static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings, const char *what,
+                                               const ColorManagedDisplay *default_display)
+{
+       if (display_settings->display_device[0] == '\0') {
+               BLI_strncpy(display_settings->display_device, default_display->name, sizeof(display_settings->display_device));
+       }
+       else {
+               ColorManagedDisplay *display = colormanage_display_get_named(display_settings->display_device);
 
-       processor = OCIO_configGetProcessor(config, (ConstTransformRcPtr *) dt);
+               if (!display) {
+                       printf("Color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
+                              display_settings->display_device, what, default_display->name);
 
-       OCIO_exponentTransformRelease(et);
-       OCIO_displayTransformRelease(dt);
-       OCIO_configRelease(config);
+                       BLI_strncpy(display_settings->display_device, default_display->name,
+                                   sizeof(display_settings->display_device));
+               }
+       }
+}
 
-       return processor;
+static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings,
+                                            ColorManagedViewSettings *view_settings, const char *what)
+{
+       ColorManagedDisplay *display;
+       ColorManagedView *default_view;
+
+       if (view_settings->view_transform[0] == '\0') {
+               display = colormanage_display_get_named(display_settings->display_device);
+               default_view = colormanage_view_get_default(display);
+
+               if (default_view)
+                       BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
+       }
+       else {
+               ColorManagedView *view = colormanage_view_get_named(view_settings->view_transform);
+
+               if (!view) {
+                       display = colormanage_display_get_named(display_settings->display_device);
+                       default_view = colormanage_view_get_default(display);
+
+                       if (default_view) {
+                               printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
+                                      what, view_settings->view_transform, default_view->name);
+
+                               BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
+                       }
+               }
+       }
+
+       /* OCIO_TODO: move to do_versions() */
+       if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
+               view_settings->exposure = 0.0f;
+               view_settings->gamma = 1.0f;
+       }
 }
 
-static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte,
-                                                  const ColorManagedViewSettings *view_settings,
-                                                  const ColorManagedDisplaySettings *display_settings)
+static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
 {
-       ConstProcessorRcPtr *processor;
-       const float gamma = view_settings->gamma;
-       const float exposure = view_settings->exposure;
-       const char *view_transform = view_settings->view_transform;
-       const char *display = display_settings->display_device;
+       if (colorspace_settings->name[0] == '\0') {
+               BLI_strncpy(colorspace_settings->name, "NONE", sizeof(colorspace_settings->name));
+       }
+       else if (!strcmp(colorspace_settings->name, "NONE")) {
+               /* pass */
+       }
+       else {
+               ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
 
-       processor = create_display_buffer_processor(view_transform, display, exposure, gamma);
+               if (!colorspace) {
+                       printf("Color management: %s colorspace \"%s\" not found, setting NONE instead.\n",
+                              what, colorspace_settings->name);
 
-       if (processor) {
-               CurveMapping *curve_mapping = NULL;
+                       BLI_strncpy(colorspace_settings->name, "NONE", sizeof(colorspace_settings->name));
+               }
+       }
+
+       (void) what;
+}
+#endif
 
-               if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
-                       curve_mapping = view_settings->curve_mapping;
+void IMB_colormanagement_check_file_config(Main *bmain)
+{
+#ifdef WITH_OCIO
+       Scene *scene;
+       Image *image;
+       MovieClip *clip;
+
+       ColorManagedDisplay *default_display;
 
-                       curvemapping_premultiply(curve_mapping, FALSE);
+       default_display = colormanage_display_get_default();
+
+       if (!default_display) {
+               /* happens when OCIO configuration is incorrect */
+               return;
+       }
+
+       for (scene = bmain->scene.first; scene; scene = scene->id.next) {
+               ColorManagedColorspaceSettings *sequencer_colorspace_settings;
+
+               colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
+               colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
+
+               sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
+
+               if (sequencer_colorspace_settings->name[0] == '\0') {
+                       BLI_strncpy(sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
                }
+               colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
+       }
 
-               display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect,
-                                             display_buffer, display_buffer_byte, curve_mapping, processor,
-                                             do_display_buffer_apply_thread);
+       /* ** check input color space settings ** */
 
-               if (curve_mapping)
-                       curvemapping_premultiply(curve_mapping, TRUE);
+       for (image = bmain->image.first; image; image = image->id.next) {
+               colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
        }
 
-       OCIO_processorRelease(processor);
+       for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
+               colormanage_check_colorspace_settings(&clip->colorspace_settings, "clip");
+       }
+#else
+       (void) bmain;
+#endif
+}
+
+void IMB_colormanagement_validate_settings(ColorManagedDisplaySettings *display_settings,
+                                           ColorManagedViewSettings *view_settings)
+{
+#ifdef WITH_OCIO
+       ColorManagedDisplay *display;
+       ColorManagedView *default_view;
+       LinkData *view_link;
+
+       display = colormanage_display_get_named(display_settings->display_device);
+       default_view = colormanage_view_get_default(display);
+
+       for (view_link = display->views.first; view_link; view_link = view_link->next) {
+               ColorManagedView *view = view_link->data;
+
+               if (!strcmp(view->name, view_settings->view_transform))
+                       break;
+       }
+
+       if (view_link == NULL)
+               BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
+#else
+       (void) display_settings;
+       (void) view_settings;
+#endif
+}
+
+const char *IMB_colormanagement_role_colorspace_name_get(int role)
+{
+#ifdef WITH_OCIO
+       switch (role) {
+               case COLOR_ROLE_SCENE_LINEAR:
+                       return global_role_scene_linear;
+                       break;
+               case COLOR_ROLE_COLOR_PICKING:
+                       return global_role_color_picking;
+                       break;
+               case COLOR_ROLE_TEXTURE_PAINTING:
+                       return global_role_texture_painting;
+                       break;
+               case COLOR_ROLE_DEFAULT_SEQUENCER:
+                       return global_role_default_sequencer;
+                       break;
+               case COLOR_ROLE_DEFAULT_FLOAT:
+                       return global_role_default_float;
+                       break;
+               case COLOR_ROLE_DEFAULT_BYTE:
+                       return global_role_default_byte;
+                       break;
+               default:
+                       printf("Unknown role was passed to %s\n", __func__);
+                       BLI_assert(0);
+       }
+#else
+       (void) role;
+#endif
+
+       return NULL;
+}
+
+void IMB_colormanagement_imbuf_float_from_rect(ImBuf *ibuf)
+{
+       int predivide = ibuf->flags & IB_cm_predivide;
+
+       if (ibuf->rect == NULL)
+               return;
+
+       if (ibuf->rect_float == NULL) {
+               if (imb_addrectfloatImBuf(ibuf) == 0)
+                       return;
+       }
+
+       /* first, create float buffer in non-linear space */
+       IMB_buffer_float_from_byte(ibuf->rect_float, (unsigned char *) ibuf->rect, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+                                  FALSE, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+
+       /* then make float be in linear space */
+       IMB_colormanagement_colorspace_to_scene_linear(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+                                                      ibuf->rect_colorspace, predivide);
+}
+
+/*********************** Threaded display buffer transform routines *************************/
+
+#ifdef WITH_OCIO
+typedef struct DisplayBufferThread {
+       ColormanageProcessor *cm_processor;
+
+       float *buffer;
+       unsigned char *byte_buffer;
+
+       float *display_buffer;
+       unsigned char *display_buffer_byte;
+
+       int width;
+       int start_line;
+       int tot_line;
+
+       int channels;
+       float dither;
+       int predivide;
+
+       int nolinear_float;
+
+       const char *byte_colorspace;
+       const char *float_colorspace;
+} DisplayBufferThread;
+
+typedef struct DisplayBufferInitData {
+       ImBuf *ibuf;
+       ColormanageProcessor *cm_processor;
+       float *buffer;
+       unsigned char *byte_buffer;
+
+       float *display_buffer;
+       unsigned char *display_buffer_byte;
+
+       int width;
+
+       const char *byte_colorspace;
+       const char *float_colorspace;
+} DisplayBufferInitData;
+
+static void display_buffer_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+{
+       DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
+       DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v;
+       ImBuf *ibuf = init_data->ibuf;
+
+       int predivide = ibuf->flags & IB_cm_predivide;
+       int channels = ibuf->channels;
+       float dither = ibuf->dither;
+
+       int offset = channels * start_line * ibuf->x;
+
+       memset(handle, 0, sizeof(DisplayBufferThread));
+
+       handle->cm_processor = init_data->cm_processor;
+
+       if (init_data->buffer)
+               handle->buffer = init_data->buffer + offset;
+
+       if (init_data->byte_buffer)
+               handle->byte_buffer = init_data->byte_buffer + offset;
+
+       if (init_data->display_buffer)
+               handle->display_buffer = init_data->display_buffer + offset;
+
+       if (init_data->display_buffer_byte)
+               handle->display_buffer_byte = init_data->display_buffer_byte + offset;
+
+       handle->width = ibuf->x;
+
+       handle->start_line = start_line;
+       handle->tot_line = tot_line;
+
+       handle->channels = channels;
+       handle->dither = dither;
+       handle->predivide = predivide;
+
+       handle->byte_colorspace = init_data->byte_colorspace;
+       handle->float_colorspace = init_data->float_colorspace;
+
+       handle->nolinear_float = ibuf->colormanage_flags & IMB_COLORMANAGE_NOLINEAR_FLOAT;
+}
+
+static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
+{
+       float *linear_buffer = NULL;
+
+       int channels = handle->channels;
+       int width = handle->width;
+       int height = handle->tot_line;
+
+       int buffer_size = channels * width * height;
+
+       int predivide = handle->predivide;
+
+       linear_buffer = MEM_callocN(buffer_size * sizeof(float), "color conversion linear buffer");
+
+       if (!handle->buffer) {
+               unsigned char *byte_buffer = handle->byte_buffer;
+
+               const char *from_colorspace = handle->byte_colorspace;
+               const char *to_colorspace = global_role_scene_linear;
+
+               float *fp;
+               unsigned char *cp;
+               int i;
+
+               /* first convert byte buffer to float, keep in image space */
+               for (i = 0, fp = linear_buffer, cp = byte_buffer;
+                    i < channels * width * height;
+                        i++, fp++, cp++)
+               {
+                       *fp = (float)(*cp) / 255.0f;
+               }
+
+               /* convert float buffer to scene linear space */
+               IMB_colormanagement_transform(linear_buffer, width, height, channels,
+                                             from_colorspace, to_colorspace, predivide);
+       }
+       else if (handle->nolinear_float) {
+               /* currently float is non-linear only in sequencer, which is working
+                * in it's own color space even to handle float buffers.
+                * This color space is the same for byte and float images.
+                * Need to convert float buffer to linear space before applying display transform
+                */
+
+               const char *from_colorspace = handle->float_colorspace;
+               const char *to_colorspace = global_role_scene_linear;
+
+               memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
+
+               IMB_colormanagement_transform(linear_buffer, width, height, channels,
+                                             from_colorspace, to_colorspace, predivide);
+       }
+       else {
+               /* some processors would want to modify float original buffer
+                * before converting it into display byte buffer, so we need to
+                * make sure original's ImBuf buffers wouldn't be modified by
+                * using duplicated buffer here
+                *
+                * NOTE: MEM_dupallocN can't be used because buffer could be
+                *       specified as an offset inside allocated buffer
+                */
+
+               memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
+       }
+
+       return linear_buffer;
+}
+
+static void *do_display_buffer_apply_thread(void *handle_v)
+{
+       DisplayBufferThread *handle = (DisplayBufferThread *) handle_v;
+       ColormanageProcessor *cm_processor = handle->cm_processor;
+       float *buffer = handle->buffer;
+       float *display_buffer = handle->display_buffer;
+       unsigned char *display_buffer_byte = handle->display_buffer_byte;
+       int channels = handle->channels;
+       int width = handle->width;
+       int height = handle->tot_line;
+       float dither = handle->dither;
+       int predivide = handle->predivide;
+
+       float *linear_buffer = display_buffer_apply_get_linear_buffer(handle);
+
+       /* apply processor */
+       IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, predivide);
+
+       /* copy result to output buffers */
+       if (display_buffer_byte) {
+               /* do conversion */
+               IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer,
+                                          channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+                                          predivide, width, height, width, width);
+       }
+
+       if (display_buffer)
+               memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
+
+       if (linear_buffer != buffer)
+               MEM_freeN(linear_buffer);
+
+       return NULL;
+}
+
+static void display_buffer_apply_threaded(ImBuf *ibuf, float *buffer, unsigned char *byte_buffer, float *display_buffer,
+                                          unsigned char *display_buffer_byte, ColormanageProcessor *cm_processor)
+{
+       DisplayBufferInitData init_data;
+
+       init_data.ibuf = ibuf;
+       init_data.cm_processor = cm_processor;
+       init_data.buffer = buffer;
+       init_data.byte_buffer = byte_buffer;
+       init_data.display_buffer = display_buffer;
+       init_data.display_buffer_byte = display_buffer_byte;
+
+       if (ibuf->rect_colorspace != NULL) {
+               init_data.byte_colorspace = ibuf->rect_colorspace->name;
+       }
+       else {
+               /* happens for viewer images, which are not so simple to determine where to
+                * set image buffer's color spaces
+                */
+               init_data.byte_colorspace = global_role_default_byte;
+       }
+
+       if (ibuf->float_colorspace != NULL) {
+               /* sequencer stores float buffers in non-linear space */
+               init_data.float_colorspace = ibuf->float_colorspace->name;
+       }
+       else {
+               init_data.float_colorspace = NULL;
+       }
+
+       IMB_processor_apply_threaded(ibuf->y, sizeof(DisplayBufferThread), &init_data,
+                                    display_buffer_init_handle, do_display_buffer_apply_thread);
+}
+
+static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte,
+                                                  const ColorManagedViewSettings *view_settings,
+                                                  const ColorManagedDisplaySettings *display_settings)
+{
+       ColormanageProcessor *cm_processor;
+
+       cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+
+       display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect,
+                                     display_buffer, display_buffer_byte, cm_processor);
+
+       IMB_colormanagement_processor_free(cm_processor);
 }
 
 static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer,
@@ -918,32 +1262,33 @@ static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *displ
 {
        colormanage_display_buffer_process_ex(ibuf, NULL, display_buffer, view_settings, display_settings);
 }
+#endif
 
-/*********************** Threaded color space transform routines *************************/
+/*********************** Threaded processor transform routines *************************/
 
-typedef struct ColorspaceTransformThread {
-       void *processor;
+typedef struct ProcessorTransformThread {
+       ColormanageProcessor *cm_processor;
        float *buffer;
        int width;
        int start_line;
        int tot_line;
        int channels;
        int predivide;
-} ColorspaceTransformThread;
+} ProcessorTransformThread;
 
-typedef struct ColorspaceTransformInit {
-       void *processor;
+typedef struct ProcessorTransformInit {
+       ColormanageProcessor *cm_processor;
        float *buffer;
        int width;
        int height;
        int channels;
        int predivide;
-} ColorspaceTransformInitData;
+} ProcessorTransformInitData;
 
-static void colorspace_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
 {
-       ColorspaceTransformThread *handle = (ColorspaceTransformThread *) handle_v;
-       ColorspaceTransformInitData *init_data = (ColorspaceTransformInitData *) init_data_v;
+       ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
+       ProcessorTransformInitData *init_data = (ProcessorTransformInitData *) init_data_v;
 
        int channels = init_data->channels;
        int width = init_data->width;
@@ -951,9 +1296,9 @@ static void colorspace_transform_init_handle(void *handle_v, int start_line, int
 
        int offset = channels * start_line * width;
 
-       memset(handle, 0, sizeof(ColorspaceTransformThread));
+       memset(handle, 0, sizeof(ProcessorTransformThread));
 
-       handle->processor = init_data->processor;
+       handle->cm_processor = init_data->cm_processor;
 
        handle->buffer = init_data->buffer + offset;
 
@@ -966,132 +1311,266 @@ static void colorspace_transform_init_handle(void *handle_v, int start_line, int
        handle->predivide = predivide;
 }
 
-static void colorspace_transform_apply_threaded(float *buffer, int width, int height, int channels,
-                                                void *processor, int predivide, void *(do_thread) (void *))
+static void *do_processor_transform_thread(void *handle_v)
 {
-       ColorspaceTransformInitData init_data;
+       ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v;
+       float *buffer = handle->buffer;
+       int channels = handle->channels;
+       int width = handle->width;
+       int height = handle->tot_line;
+       int predivide = handle->predivide;
 
-       init_data.processor = processor;
+       IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide);
+
+       return NULL;
+}
+
+static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels,
+                                               ColormanageProcessor *cm_processor, int predivide)
+{
+       ProcessorTransformInitData init_data;
+
+       init_data.cm_processor = cm_processor;
        init_data.buffer = buffer;
        init_data.width = width;
        init_data.height = height;
        init_data.channels = channels;
        init_data.predivide = predivide;
 
-       IMB_processor_apply_threaded(height, sizeof(ColorspaceTransformThread), &init_data,
-                                    colorspace_transform_init_handle, do_thread);
+       IMB_processor_apply_threaded(height, sizeof(ProcessorTransformThread), &init_data,
+                                    processor_transform_init_handle, do_processor_transform_thread);
 }
 
-static void *do_color_space_transform_thread(void *handle_v)
+/*********************** Color space transformation functions *************************/
+
+/* convert the whole buffer from specified by name color space to another - internal implementation */
+static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace,
+                                         const char *to_colorspace, int predivide, int do_threaded)
 {
-       ColorspaceTransformThread *handle = (ColorspaceTransformThread *) handle_v;
-       ConstProcessorRcPtr *processor = (ConstProcessorRcPtr *) handle->processor;
-       PackedImageDesc *img;
-       float *buffer = handle->buffer;
-       int channels = handle->channels;
-       int width = handle->width;
-       int height = handle->tot_line;
-       int predivide = handle->predivide;
+       ColormanageProcessor *cm_processor;
 
-       img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float),
-                                        channels * sizeof(float), channels * sizeof(float) * width);
+       if (!strcmp(from_colorspace, "NONE")) {
+               return;
+       }
+
+       if (!strcmp(from_colorspace, to_colorspace)) {
+               /* if source and destination color spaces are identical, skip
+                * threading overhead and simply do nothing
+                */
+               return;
+       }
 
-       if (predivide)
-               OCIO_processorApply_predivide(processor, img);
+       cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
+
+       if (do_threaded)
+               processor_transform_apply_threaded(buffer, width, height, channels, cm_processor, predivide);
        else
-               OCIO_processorApply(processor, img);
+               IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
 
-       OCIO_packedImageDescRelease(img);
+       IMB_colormanagement_processor_free(cm_processor);
+}
 
-       return NULL;
+/* convert the whole buffer from specified by name color space to another */
+void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
+                                   const char *from_colorspace, const char *to_colorspace, int predivide)
+{
+       colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, FALSE);
 }
 
-static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
-                                                                  const char *to_colorspace)
+/* convert the whole buffer from specified by name color space to another
+ * will do threaded conversion
+ */
+void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels,
+                                            const char *from_colorspace, const char *to_colorspace, int predivide)
 {
-       ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+       colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, TRUE);
+}
+
+void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
+{
+       ColormanageProcessor *cm_processor;
+
+       if (!strcmp(from_colorspace, "NONE")) {
+               return;
+       }
+
+       if (!strcmp(from_colorspace, to_colorspace)) {
+               /* if source and destination color spaces are identical, skip
+                * threading overhead and simply do nothing
+                */
+               return;
+       }
+
+       cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
+
+       IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
+
+       IMB_colormanagement_processor_free(cm_processor);
+}
+
+/* convert pixel from specified by descriptor color space to scene linear
+ * used by performance-critical areas such as renderer and baker
+ */
+void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
+{
+#ifdef WITH_OCIO
        ConstProcessorRcPtr *processor;
 
-       processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
+       if (!colorspace) {
+               /* OCIO_TODO: make sure it never happens */
 
-       return processor;
+               printf("%s: perform conversion from unknown color space\n", __func__);
+
+               return;
+       }
+
+       processor = colorspace_to_scene_linear_processor(colorspace);
+
+       if (processor)
+               OCIO_processorApplyRGB(processor, pixel);
+#else
+       (void) pixel;
+       (void) colorspace;
+#endif
+}
+
+/* same as above, but converts colors in opposite direction */
+void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
+{
+#ifdef WITH_OCIO
+       ConstProcessorRcPtr *processor;
+
+       if (!colorspace) {
+               /* OCIO_TODO: make sure it never happens */
+
+               printf("%s: perform conversion from unknown color space\n", __func__);
+
+               return;
+       }
+
+       processor = colorspace_from_scene_linear_processor(colorspace);
+
+       if (processor)
+               OCIO_processorApplyRGB(processor, pixel);
+
+#else
+       (void) pixel;
+       (void) colorspace;
+#endif
 }
+
+void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide)
+{
+#ifdef WITH_OCIO
+       ConstProcessorRcPtr *processor;
+
+       if (!colorspace) {
+               /* OCIO_TODO: make sure it never happens */
+
+               printf("%s: perform conversion from unknown color space\n", __func__);
+
+               return;
+       }
+
+       processor = colorspace_to_scene_linear_processor(colorspace);
+
+       if (processor) {
+               PackedImageDesc *img;
+
+               img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float),
+                                                channels * sizeof(float), channels * sizeof(float) * width);
+
+               if (predivide)
+                       OCIO_processorApply_predivide(processor, img);
+               else
+                       OCIO_processorApply(processor, img);
+
+               OCIO_packedImageDescRelease(img);
+       }
+#else
+       (void) buffer;
+       (void) channels;
+       (void) width;
+       (void) height;
+       (void) colorspace;
+       (void) predivide;
+#endif
+}
+
+/* convert pixel from scene linear to display space using default view
+ * used by performance-critical areas such as color-related widgets where we want to reduce
+ * amount of per-widget allocations
+ */
+void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
+{
+#ifdef WITH_OCIO
+       ConstProcessorRcPtr *processor;
+
+       processor = display_from_scene_linear_processor(display);
+
+       if (processor)
+               OCIO_processorApplyRGB(processor, pixel);
+#else
+       (void) pixel;
+       (void) display;
 #endif
+}
 
-void IMB_colormanagement_colorspace_transform(float *buffer, int width, int height, int channels,
-                                              const char *from_colorspace, const char *to_colorspace,
-                                              int predivide)
+/* same as above, but converts color in opposite direction */
+void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
 {
 #ifdef WITH_OCIO
        ConstProcessorRcPtr *processor;
 
-       if (!strcmp(from_colorspace, "NONE")) {
-               return;
-       }
+       processor = display_to_scene_linear_processor(display);
 
-       if (!strcmp(from_colorspace, to_colorspace)) {
-               /* if source and destination color spaces are identical, skip
-                * threading overhead and simply do nothing
-                */
-               return;
-       }
+       if (processor)
+               OCIO_processorApplyRGB(processor, pixel);
+#else
+       (void) pixel;
+       (void) display;
+#endif
+}
 
-       processor = create_colorspace_transform_processor(from_colorspace, to_colorspace);
+void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4],
+                                                   const ColorManagedViewSettings *view_settings,
+                                                   const ColorManagedDisplaySettings *display_settings)
+{
+       ColormanageProcessor *cm_processor;
 
-       if (processor) {
-               colorspace_transform_apply_threaded(buffer, width, height, channels, processor, predivide,
-                                                   do_color_space_transform_thread);
+       copy_v4_v4(result, pixel);
 
-               OCIO_processorRelease(processor);
-       }
-#else
-       (void) buffer;
-       (void) width;
-       (void) height;
-       (void) channels;
-       (void) from_colorspace;
-       (void) to_colorspace;
-#endif
+       cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+       IMB_colormanagement_processor_apply_v4(cm_processor, result);
+       IMB_colormanagement_processor_free(cm_processor);
 }
 
-#ifdef WITH_OCIO
-static char *role_colorspace_name_get(int role)
+void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float pixel[3],
+                                                   const ColorManagedViewSettings *view_settings,
+                                                   const ColorManagedDisplaySettings *display_settings)
 {
-       switch (role) {
-               case COLOR_ROLE_SCENE_LINEAR:
-                       return global_role_scene_linear;
-                       break;
-               case COLOR_ROLE_COLOR_PICKING:
-                       return global_role_color_picking;
-                       break;
-               case COLOR_ROLE_TEXTURE_PAINTING:
-                       return global_role_texture_painting;
-                       break;
-               case COLOR_ROLE_SEQUENCER:
-                       return global_role_sequencer;
-                       break;
-               default:
-                       printf("Unknown role was passed to %s\n", __func__);
-                       BLI_assert(0);
-       }
+       ColormanageProcessor *cm_processor;
 
-       return NULL;
+       copy_v3_v3(result, pixel);
+
+       cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+       IMB_colormanagement_processor_apply_v3(cm_processor, result);
+       IMB_colormanagement_processor_free(cm_processor);
 }
-#endif
 
 void IMB_colormanagement_imbuf_to_role(ImBuf *ibuf, int role)
 {
 #ifdef WITH_OCIO
        if (ibuf->rect_float) {
                const char *from_colorspace = global_role_scene_linear;
-               const char *to_colorspace = role_colorspace_name_get(role);
+               const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
                int predivide = ibuf->flags & IB_cm_predivide;
 
                if (ibuf->rect)
                        imb_freerectImBuf(ibuf);
 
-               IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-                                                        from_colorspace, to_colorspace, predivide);
+               IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+                                                      from_colorspace, to_colorspace, predivide);
        }
 #else
        (void) ibuf;
@@ -1103,15 +1582,15 @@ void IMB_colormanagement_imbuf_from_role(ImBuf *ibuf, int role)
 {
 #ifdef WITH_OCIO
        if (ibuf->rect_float) {
-               const char *from_colorspace = role_colorspace_name_get(role);
+               const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
                const char *to_colorspace = global_role_scene_linear;
                int predivide = ibuf->flags & IB_cm_predivide;
 
                if (ibuf->rect)
                        imb_freerectImBuf(ibuf);
 
-               IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-                                                        from_colorspace, to_colorspace, predivide);
+               IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+                                                      from_colorspace, to_colorspace, predivide);
        }
 #else
        (void) ibuf;
@@ -1119,12 +1598,12 @@ void IMB_colormanagement_imbuf_from_role(ImBuf *ibuf, int role)
 #endif
 }
 
-void IMB_colormanagement_pixel_to_role(float pixel[4], int role)
+void IMB_colormanagement_pixel_to_role_v4(float pixel[4], int role)
 {
 #ifdef WITH_OCIO
                ConstProcessorRcPtr *processor;
                const char *from_colorspace = global_role_scene_linear;
-               const char *to_colorspace = role_colorspace_name_get(role);
+               const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
 
                processor = create_colorspace_transform_processor(from_colorspace, to_colorspace);
 
@@ -1139,11 +1618,11 @@ void IMB_colormanagement_pixel_to_role(float pixel[4], int role)
 #endif
 }
 
-void IMB_colormanagement_pixel_from_role(float pixel[4], int role)
+void IMB_colormanagement_pixel_from_role_v4(float pixel[4], int role)
 {
 #ifdef WITH_OCIO
                ConstProcessorRcPtr *processor;
-               const char *from_colorspace = role_colorspace_name_get(role);
+               const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
                const char *to_colorspace = global_role_scene_linear;
 
                processor = create_colorspace_transform_processor(from_colorspace, to_colorspace);
@@ -1159,15 +1638,54 @@ void IMB_colormanagement_pixel_from_role(float pixel[4], int role)
 #endif
 }
 
+void IMB_colormanagement_imbuf_assign_spaces(ImBuf *ibuf, ColorManagedColorspaceSettings *colorspace_settings)
+{
+#ifdef WITH_OCIO
+       /* OCIO_TODO: get rid of NONE color space */
+       if (colorspace_settings) {
+               if (colorspace_settings->name[0] == 0 || !strcmp(colorspace_settings->name, "NONE")) {
+                       /* when opening new image, assign it's color space based on default roles */
+
+                       if (ibuf->rect_float)
+                               BLI_strncpy(colorspace_settings->name, global_role_default_float, MAX_COLORSPACE_NAME);
+                       else
+                               BLI_strncpy(colorspace_settings->name, global_role_default_byte, MAX_COLORSPACE_NAME);
+               }
+
+               ibuf->rect_colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
+       }
+       else {
+               if (ibuf->rect_float)
+                       ibuf->rect_colorspace = colormanage_colorspace_get_named(global_role_default_float);
+               else
+                       ibuf->rect_colorspace = colormanage_colorspace_get_named(global_role_default_byte);
+       }
+#else
+       (void) ibuf;
+       (void) colorspace_settings;
+#endif
+}
+
+void IMB_colormanagement_imbuf_assign_float_space(ImBuf *ibuf, ColorManagedColorspaceSettings *colorspace_settings)
+{
+       ibuf->float_colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
+}
+
 void IMB_colormanagement_imbuf_make_scene_linear(ImBuf *ibuf, ColorManagedColorspaceSettings *colorspace_settings)
 {
 #ifdef WITH_OCIO
+       /* for byte buffers only store it's color space, no affect on buffer itself
+        * that's because of precision issues of bytes
+        */
+       IMB_colormanagement_imbuf_assign_spaces(ibuf, colorspace_settings);
+
+       /* convert float buffer to scene linear space */
        if (ibuf->rect_float) {
                const char *from_colorspace = colorspace_settings->name;
                const char *to_colorspace = global_role_scene_linear;
                int predivide = ibuf->flags & IB_cm_predivide;
 
-               IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+               IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
                                                         from_colorspace, to_colorspace, predivide);
        }
 #else
@@ -1200,16 +1718,6 @@ void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManage
 #endif
 }
 
-#ifdef WITH_OCIO
-static void colormanage_flags_allocate(ImBuf *ibuf)
-{
-       if (global_tot_display == 0)
-               return;
-
-       ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display, "imbuf display_buffer_flags");
-}
-#endif
-
 static void imbuf_verify_float(ImBuf *ibuf)
 {
        /* multiple threads could request for display buffer at once and in case
@@ -1231,90 +1739,49 @@ static void imbuf_verify_float(ImBuf *ibuf)
 
 /*********************** Public display buffers interfaces *************************/
 
-void IMB_colormanage_cache_free(ImBuf *ibuf)
-{
-       if (ibuf->display_buffer_flags) {
-               MEM_freeN(ibuf->display_buffer_flags);
-
-               ibuf->display_buffer_flags = NULL;
-       }
-
-       if (ibuf->colormanage_cache) {
-               ColormnaageCacheData *cache_data = colormanage_cachedata_get(ibuf);
-               struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
-
-               if (cache_data) {
-                       MEM_freeN(cache_data);
-               }
-
-               if (moviecache) {
-                       IMB_moviecache_free(moviecache);
-               }
-
-               MEM_freeN(ibuf->colormanage_cache);
-
-               ibuf->colormanage_cache = NULL;
-       }
-}
-
+/* acquire display buffer for given image buffer using specified view and display settings */
 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
                                           const ColorManagedDisplaySettings *display_settings, void **cache_handle)
 {
        *cache_handle = NULL;
 
-#ifdef WITH_OCIO
-
        if (!ibuf->x || !ibuf->y)
                return NULL;
 
-#if !defined(COLORMANAGE_BYTE_BUFFER)
-       if (!ibuf->rect_float) {
-               imbuf_verify_float(ibuf);
-
-               return (unsigned char *) ibuf->rect;
-       }
-#endif
-
        if (global_tot_display == 0 || global_tot_view == 0) {
-               /* currently only view-transformation is allowed, input and display
-                * spaces are hard-coded, so if there's no view transform applying
-                * it's safe to suppose standard byte buffer is used for display
+               /* if there's no view transform or display transforms, fallback to standard sRGB/linear conversion
+                * the same logic would be used if OCIO is disabled
                 */
 
                imbuf_verify_float(ibuf);
 
                return (unsigned char *) ibuf->rect;
        }
+#ifdef WITH_OCIO
        else {
                unsigned char *display_buffer;
                int buffer_size;
                ColormanageCacheViewSettings cache_view_settings;
                ColormanageCacheDisplaySettings cache_display_settings;
 
-               if (ibuf->userflags & IB_RECT_INVALID) {
-                       /* if byte buffer is marked as invalid, it means that float buffer was modified
-                        * and display buffer should be updated
-                        * mark all existing color managed display buffers as invalid, also free
-                        * legacy byte buffer to be sure all users would re-calculate display buffers
-                        * after removing RECT_INVALID flag
-                        */
-
-                       IMB_display_buffer_invalidate(ibuf);
-
-                       if (ibuf->rect)
-                               imb_freerectImBuf(ibuf);
-
-                       ibuf->userflags &= ~IB_RECT_INVALID;
-               }
-
                colormanage_view_settings_to_cache(&cache_view_settings, view_settings);
                colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
 
                BLI_lock_thread(LOCK_COLORMANAGE);
 
                /* ensure color management bit fields exists */
-               if (!ibuf->display_buffer_flags)
-                       colormanage_flags_allocate(ibuf);
+               if (!ibuf->display_buffer_flags) {
+                       if (global_tot_display)
+                               ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display, "imbuf display_buffer_flags");
+               }
+                else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
+                       /* all display buffers were marked as invalid from other areas,
+                        * now propagate this flag to internal color management routines
+                        */
+                       memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
+
+                       ibuf->userflags &= ~IB_DISPLAY_BUFFER_INVALID;
+               }
 
                display_buffer = colormanage_cache_get(ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
 
@@ -1334,273 +1801,91 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
 
                return display_buffer;
        }
-#else
-       /* no OCIO support, simply return byte buffer which was
-        * generated from float buffer (if any) using standard
-        * profiles without applying any view / display transformation */
-
-       (void) view_settings;
-       (void) display_settings;
-
-       imbuf_verify_float(ibuf);
-
-       return (unsigned char*) ibuf->rect;
-#endif
-}
-
-static void display_transform_settings_get(const bContext *C, ColorManagedViewSettings **view_settings_r, ColorManagedDisplaySettings **display_settings_r)
-{
-       Scene *scene = CTX_data_scene(C);
-
-       *view_settings_r = &scene->view_settings;
-       *display_settings_r = &scene->display_settings;
-}
-
-unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
-{
-       ColorManagedViewSettings *view_settings;
-       ColorManagedDisplaySettings *display_settings;
-
-       display_transform_settings_get(C, &view_settings, &display_settings);
-
-       return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
-}
-
-void IMB_display_buffer_pixel(float result[4], const float pixel[4],  const ColorManagedViewSettings *view_settings,
-                              const ColorManagedDisplaySettings *display_settings)
-{
-#ifdef WITH_OCIO
-       ConstProcessorRcPtr *processor;
-       const float gamma = view_settings->gamma;
-       const float exposure = view_settings->exposure;
-       const char *view_transform = view_settings->view_transform;
-       const char *display = display_settings->display_device;
-
-       copy_v4_v4(result, pixel);
-
-       processor = create_display_buffer_processor(view_transform, display, exposure, gamma);
-
-       if (processor) {
-
-               if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
-                       CurveMapping *curve_mapping = NULL;
-
-                       /* curve mapping could be used meanwhile to compute display buffer,
-                        * so need to lock here to be sure we're not changing curve mapping
-                        * from separated threads
-                        */
-                       BLI_lock_thread(LOCK_COLORMANAGE);
-
-                       curve_mapping = view_settings->curve_mapping;
-
-                       curvemapping_premultiply(curve_mapping, FALSE);
-
-                       curvemapping_evaluate_premulRGBF(curve_mapping, result, result);
-                       OCIO_processorApplyRGBA(processor, result);
-
-                       curvemapping_premultiply(curve_mapping, TRUE);
-
-                       BLI_unlock_thread(LOCK_COLORMANAGE);
-               }
-               else {
-                       OCIO_processorApplyRGBA(processor, result);
-               }
-       }
-#else
-       (void) view_settings;
-       (void) display_settings;
-
-       copy_v4_v4(result, pixel);
-#endif
-}
-
-/* covert float buffer to display space and store it in image buffer's byte array */
-void IMB_display_buffer_to_imbuf_rect(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
-                                      const ColorManagedDisplaySettings *display_settings)
-{
-#ifdef WITH_OCIO
-
-#if !defined(COLORMANAGE_BYTE_BUFFER)
-       if (!ibuf->rect_float)
-               return;
-#endif
-
-       if (global_tot_display == 0 || global_tot_view == 0) {
-               imbuf_verify_float(ibuf);
-       }
-       else {
-               if (!ibuf->rect) {
-                       imb_addrectImBuf(ibuf);
-               }
-
-               colormanage_display_buffer_process(ibuf, (unsigned char *) ibuf->rect, view_settings, display_settings);
-       }
 #else
        (void) view_settings;
        (void) display_settings;
 
-       imbuf_verify_float(ibuf);
-#endif
-}
-
-void IMB_display_buffer_release(void *cache_handle)
-{
-       if (cache_handle) {
-               BLI_lock_thread(LOCK_COLORMANAGE);
-
-               colormanage_cache_handle_release(cache_handle);
-
-               BLI_unlock_thread(LOCK_COLORMANAGE);
-       }
-}
-
-void IMB_display_buffer_invalidate(ImBuf *ibuf)
-{
-       /* if there's no display_buffer_flags this means there's no color managed
-        * buffers created for this imbuf, no need to invalidate
-        */
-       if (ibuf->display_buffer_flags) {
-               memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
-       }
-}
-
-#ifdef WITH_OCIO
-static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings, const char *what,
-                                               const ColorManagedDisplay *default_display)
-{
-       if (display_settings->display_device[0] == '\0') {
-               BLI_strncpy(display_settings->display_device, default_display->name, sizeof(display_settings->display_device));
-       }
-       else {
-               ColorManagedDisplay *display = colormanage_display_get_named(display_settings->display_device);
-
-               if (!display) {
-                       printf("Blender color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
-                              display_settings->display_device, what, default_display->name);
-
-                       BLI_strncpy(display_settings->display_device, default_display->name,
-                                   sizeof(display_settings->display_device));
-               }
-       }
-}
-
-static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings, const char *what)
-{
-       ColorManagedDisplay *display;
-       ColorManagedView *default_view;
-
-       if (view_settings->view_transform[0] == '\0') {
-               display = colormanage_display_get_named(display_settings->display_device);
-               default_view = colormanage_view_get_default(display);
-
-               if (default_view)
-                       BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
-       }
-       else {
-               ColorManagedView *view = colormanage_view_get_named(view_settings->view_transform);
-
-               if (!view) {
-                       display = colormanage_display_get_named(display_settings->display_device);
-                       default_view = colormanage_view_get_default(display);
-
-                       if (default_view) {
-                               printf("Blender color management: %s view \"%s\" not found, setting default \"%s\".\n",
-                                      what, view_settings->view_transform, default_view->name);
+       return NULL;
+#endif
+}
 
-                               BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
-                       }
-               }
-       }
+/* same as IMB_display_buffer_acquire but gets view and display settings from context */
+unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
+{
+       ColorManagedViewSettings *view_settings;
+       ColorManagedDisplaySettings *display_settings;
 
-       /* OCIO_TODO: move to do_versions() */
-       if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
-               view_settings->exposure = 0.0f;
-               view_settings->gamma = 1.0f;
-       }
+       display_transform_get_from_ctx(C, &view_settings, &display_settings);
+
+       return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
 }
 
-static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
+/* covert float buffer to display space and store it in image buffer's byte array */
+void IMB_display_buffer_to_imbuf_rect(ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
+                                      const ColorManagedDisplaySettings *display_settings)
 {
-       if (colorspace_settings->name[0] == '\0') {
-               BLI_strncpy(colorspace_settings->name, "NONE", sizeof(colorspace_settings->name));
-       }
-       else if (!strcmp(colorspace_settings->name, "NONE")) {
-               /* pass */
+#ifdef WITH_OCIO
+       if (global_tot_display == 0 || global_tot_view == 0) {
+               imbuf_verify_float(ibuf);
        }
        else {
-               ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
-
-               if (!colorspace) {
-                       printf("Blender color management: %s colorspace \"%s\" not found, setting NONE instead.\n",
-                              what, colorspace_settings->name);
-
-                       BLI_strncpy(colorspace_settings->name, "NONE", sizeof(colorspace_settings->name));
+               if (!ibuf->rect) {
+                       imb_addrectImBuf(ibuf);
                }
+
+               colormanage_display_buffer_process(ibuf, (unsigned char *) ibuf->rect, view_settings, display_settings);
        }
+#else
+       (void) view_settings;
+       (void) display_settings;
 
-       (void) what;
-}
+       imbuf_verify_float(ibuf);
 #endif
+}
 
-void IMB_colormanagement_check_file_config(Main *bmain)
+void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height,
+                                        int channels, const ColorManagedViewSettings *view_settings,
+                                        const ColorManagedDisplaySettings *display_settings, int predivide)
 {
 #ifdef WITH_OCIO
-       Scene *scene;
-       Image *image;
-       MovieClip *clip;
-
-       ColorManagedDisplay *default_display;
-
-       default_display = colormanage_display_get_default();
-
-       if (!default_display) {
-               /* happens when OCIO configuration is incorrect */
-               return;
+       if (global_tot_display == 0 || global_tot_view == 0) {
+               IMB_buffer_byte_from_float(display_buffer, linear_buffer, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, FALSE,
+                                          width, height, width, width);
        }
+       else {
+               float *buffer;
+               ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
 
-       for (scene = bmain->scene.first; scene; scene = scene->id.next) {
-               colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
-               colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
-       }
+               buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer");
+               memcpy(buffer, linear_buffer, channels * width * height * sizeof(float));
 
-       /* ** check input color space settings ** */
+               IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
 
-       for (image = bmain->image.first; image; image = image->id.next) {
-               colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
-       }
+               IMB_colormanagement_processor_free(cm_processor);
 
-       for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
-               colormanage_check_colorspace_settings(&clip->colorspace_settings, "clip");
+               IMB_buffer_byte_from_float(display_buffer, buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
+                                          FALSE, width, height, width, width);
+
+               MEM_freeN(buffer);
        }
 #else
-       (void) bmain;
+       (void) view_settings;
+       (void) display_settings;
+
+       IMB_buffer_byte_from_float(display_buffer, linear_buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide,
+                                  width, height, width, width);
 #endif
 }
 
-void IMB_colormanagement_validate_settings(ColorManagedDisplaySettings *display_settings,
-                                           ColorManagedViewSettings *view_settings)
+void IMB_display_buffer_release(void *cache_handle)
 {
-#ifdef WITH_OCIO
-       ColorManagedDisplay *display;
-       ColorManagedView *default_view;
-       LinkData *view_link;
-
-       display = colormanage_display_get_named(display_settings->display_device);
-       default_view = colormanage_view_get_default(display);
+       if (cache_handle) {
+               BLI_lock_thread(LOCK_COLORMANAGE);
 
-       for (view_link = display->views.first; view_link; view_link = view_link->next) {
-               ColorManagedView *view = view_link->data;
+               colormanage_cache_handle_release(cache_handle);
 
-               if (!strcmp(view->name, view_settings->view_transform))
-                       break;
+               BLI_unlock_thread(LOCK_COLORMANAGE);
        }
-
-       if (view_link == NULL)
-               BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
-#else
-       (void) display_settings;
-       (void) view_settings;
-#endif
 }
 
 /*********************** Display functions *************************/
@@ -1705,10 +1990,16 @@ const char *IMB_colormanagement_display_get_default_name(void)
 #endif
 }
 
+/* used by performance-critical pixel processing areas, such as color widgets */
+ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
+{
+       return colormanage_display_get_named(name);
+}
+
 /*********************** View functions *************************/
 
 #ifdef WITH_OCIO
-ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display)
+const char *colormanage_view_get_default_name(const ColorManagedDisplay *display)
 {
        ConstConfigRcPtr *config = OCIO_getCurrentConfig();
        const char *name;
@@ -1723,7 +2014,14 @@ ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *displa
 
        OCIO_configRelease(config);
 
-       if (name[0] == '\0')
+       return name;
+}
+
+ColorManagedView *colormanage_view_get_default(const ColorManagedDisplay *display)
+{
+       const char *name = colormanage_view_get_default_name(display);
+
+       if (!name || name[0] == '\0')
                return NULL;
 
        return colormanage_view_get_named(name);
@@ -1786,6 +2084,22 @@ const char *IMB_colormanagement_view_get_indexed_name(int index)
        return "NONE";
 }
 
+const char *IMB_colormanagement_view_get_default_name(const char *display_name)
+{
+#if WITH_OCIO
+       ColorManagedDisplay *display = colormanage_display_get_named(display_name);
+       ColorManagedView *view = colormanage_view_get_default(display);
+
+       if (view) {
+               return view->name;
+       }
+#else
+       (void) display_name;
+#endif
+
+       return NULL;
+}
+
 /*********************** Color space functions *************************/
 
 static void colormanage_description_strip(char *description)
@@ -1949,222 +2263,283 @@ void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *tot
  * Partial display update is supposed to be used by such areas as
  * compositor and renderer, This areas are calculating tiles of the
  * images and because of performance reasons only this tiles should
- * be color managed when they finished to be calculated. This gives
- * nice visual feedback without slowing things down.
+ * be color managed.
+ * This gives nice visual feedback without slowing things down.
  *
- * Updating happens for all display buffers generated for given
- * ImBuf at the time function is being called.
+ * Updating happens for active display transformation only, all
+ * the rest buffers would be marked as dirty
  */
 
-static void partial_buffer_update_rect(unsigned char *display_buffer, const float *linear_buffer, int display_stride,
-                                                                          int linear_stride, int linear_offset_x, int linear_offset_y,
-                                                                          int channels, int dither, int predivide, int profile_from,
-                                                                          ConstProcessorRcPtr *processor, int xmin, int ymin, int xmax, int ymax)
+#ifdef WITH_OCIO
+static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffer, const float *linear_buffer,
+                                       const unsigned char *byte_buffer, int display_stride, int linear_stride,
+                                       int linear_offset_x, int linear_offset_y, ColormanageProcessor *cm_processor,
+                                       int xmin, int ymin, int xmax, int ymax)
 {
        int x, y;
+       int channels = ibuf->channels;
+       int predivide = ibuf->flags & IB_cm_predivide;
+       float dither = ibuf->dither;
+       ColorSpace *rect_colorspace = ibuf->rect_colorspace;
+       float *display_buffer_float = NULL;
+       int width = xmax - xmin;
+       int height = ymax - ymin;
 
-       (void) processor; /* silent down compiler when building without OCIO */
-
-       if (profile_from == IB_PROFILE_NONE)
-               profile_from = IB_PROFILE_SRGB;
+       if (dither != 0.0f) {
+               display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither");
+       }
 
        for (y = ymin; y < ymax; y++) {
                for (x = xmin; x < xmax; x++) {
                        int display_index = (y * display_stride + x) * channels;
                        int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
+                       float pixel[4];
 
-#ifdef WITH_OCIO
-                       if (processor) {
-                               float pixel[4];
-
+                       if (linear_buffer) {
                                copy_v4_v4(pixel, (float *) linear_buffer + linear_index);
+                       }
+                       else if (byte_buffer) {
+                               rgba_uchar_to_float(pixel, byte_buffer + linear_index);
 
-                               if (predivide)
-                                       OCIO_processorApplyRGBA_predivide(processor, pixel);
-                               else
-                                       OCIO_processorApplyRGBA(processor, pixel);
-
-                               rgba_float_to_uchar(display_buffer + display_index, pixel);
+                               IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
                        }
+
+                       if (predivide)
+                               IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
                        else
-#endif
-                       {
-                               IMB_buffer_byte_from_float(display_buffer + display_index, linear_buffer + linear_index, channels,
-                                                          dither, IB_PROFILE_SRGB, profile_from, predivide, 1, 1, 1, 1);
+                               IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
+
+                       if (display_buffer_float) {
+                               int index = ((y - ymin) * width + (x - xmin)) * channels;
+
+                               copy_v4_v4(display_buffer_float + index, pixel);
+                       }
+                       else {
+                               rgba_float_to_uchar(display_buffer + display_index, pixel);
                        }
                }
        }
+
+       if (display_buffer_float) {
+               int display_index = (ymin * display_stride + xmin) * channels;
+
+               IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither,
+                                          IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, width, height, display_stride, width);
+
+               MEM_freeN(display_buffer_float);
+       }
 }
+#endif
 
-void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, int stride, int offset_x, int offset_y,
+void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer,
+                                       int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings,
+                                       const ColorManagedDisplaySettings *display_settings,
                                        int xmin, int ymin, int xmax, int ymax)
 {
-       int channels = ibuf->channels;
-       int predivide = ibuf->flags & IB_cm_predivide;
-       int dither = ibuf->dither;
-       int profile_from = ibuf->profile;
-       int display;
-       int *display_buffer_flags;
+       if (ibuf->rect && ibuf->rect_float) {
+               /* update byte buffer created by legacy color management */
 
-#ifdef WITH_OCIO
+               unsigned char *rect = (unsigned char *) ibuf->rect;
+               int predivide = ibuf->flags & IB_cm_predivide;
+               int channels = ibuf->channels;
+               int profile_from = ibuf->profile;
+               int width = xmax - xmin;
+               int height = ymax - ymin;
+               int rect_index = (ymin * ibuf->x + xmin) * channels;
+               int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels;
 
-       BLI_lock_thread(LOCK_COLORMANAGE);
+               if (profile_from == IB_PROFILE_NONE)
+                       profile_from = IB_PROFILE_LINEAR_RGB;
 
-       if (ibuf->rect && ibuf->rect_float) {
-               /* update byte buffer created by legacy color management */
-               partial_buffer_update_rect((unsigned char *) ibuf->rect, linear_buffer, ibuf->x, stride, offset_x, offset_y,
-                                      channels, dither, predivide, profile_from, NULL, xmin, ymin, xmax, ymax);
+               IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither,
+                                          IB_PROFILE_SRGB, profile_from, predivide, width, height, ibuf->x, stride);
        }
 
-       if (!ibuf->display_buffer_flags) {
-               /* there's no cached display buffers, so no need to iterate though bit fields */
+#ifdef WITH_OCIO
+       if (ibuf->display_buffer_flags) {
+               ColormanageCacheViewSettings cache_view_settings;
+               ColormanageCacheDisplaySettings cache_display_settings;
+               void *cache_handle = NULL;
+               unsigned char *display_buffer = NULL;
+               int view_flag, display_index, buffer_width;
+
+               colormanage_view_settings_to_cache(&cache_view_settings, view_settings);
+               colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
 
-               BLI_unlock_thread(LOCK_COLORMANAGE);
+               view_flag = 1 << (cache_view_settings.view - 1);
+               display_index = cache_display_settings.display - 1;
 
-               return;
-       }
+               BLI_lock_thread(LOCK_COLORMANAGE);
+               if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0)
+                       display_buffer = colormanage_cache_get(ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
 
-       /* make a copy of flags, so other areas could calculate new display buffers
-        * and they'll be properly handled later
-        */
-       display_buffer_flags = MEM_dupallocN(ibuf->display_buffer_flags);
+               /* in some rare cases buffer's dimension could be changing directly from
+                * different thread
+                * this i.e. happens when image editor acquires render result
+                */
+               buffer_width = ibuf->x;
 
-       BLI_unlock_thread(LOCK_COLORMANAGE);
+               /* mark all other buffers as invalid */
+               memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
+               ibuf->display_buffer_flags[display_index] |= view_flag;
 
-       for (display = 0; display < global_tot_display; display++) {
-               ColormanageCacheDisplaySettings display_settings = {0};
-               int display_index = display + 1; /* displays in configuration are 1-based */
-               const char *display_name = IMB_colormanagement_display_get_indexed_name(display_index);
-               int view_flags = display_buffer_flags[display];
-               int view = 0;
-
-               display_settings.display = display_index;
-
-               while (view_flags != 0) {
-                       if (view_flags % 2 == 1) {
-                               ColormanageCacheViewSettings view_settings = {0};
-                               unsigned char *display_buffer;
-                               void *cache_handle = NULL;
-                               int view_index = view + 1; /* views in configuration are 1-based */
-                               float exposure, gamma;
-                               int buffer_width;
-
-                               view_settings.view = view_index;
-
-                               BLI_lock_thread(LOCK_COLORMANAGE);
-                               display_buffer = colormanage_cache_get_cache_data(ibuf, &view_settings, &display_settings,
-                                                                                 &cache_handle, &exposure, &gamma);
-
-                               /* in some rare cases buffer's dimension could be changing directly from
-                                * different thread
-                                * this i.e. happens when image editor acquires render result
-                                */
-                               buffer_width = ibuf->x;
-                               BLI_unlock_thread(LOCK_COLORMANAGE);
-
-                               if (display_buffer) {
-                                       const char *view_name = IMB_colormanagement_view_get_indexed_name(view_index);
-                                       ConstProcessorRcPtr *processor = NULL;
-
-                                       processor = create_display_buffer_processor(view_name, display_name, exposure, gamma);
-
-                                       partial_buffer_update_rect(display_buffer, linear_buffer, buffer_width, stride,
-                                               offset_x, offset_y, channels, dither, predivide, profile_from,
-                                               processor, xmin, ymin, xmax, ymax);
-
-                                       if (processor)
-                                               OCIO_processorRelease(processor);
-                               }
+               BLI_unlock_thread(LOCK_COLORMANAGE);
 
-                               IMB_display_buffer_release(cache_handle);
-                       }
+               if (display_buffer) {
+                       ColormanageProcessor *cm_processor;
+
+                       cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
 
-                       view_flags /= 2;
-                       view++;
+                       partial_buffer_update_rect(ibuf, display_buffer, linear_buffer, byte_buffer, buffer_width, stride,
+                                                  offset_x, offset_y, cm_processor, xmin, ymin, xmax, ymax);
+
+                       IMB_colormanagement_processor_free(cm_processor);
+
+                       IMB_display_buffer_release(cache_handle);
                }
        }
-
-       MEM_freeN(display_buffer_flags);
 #else
-       (void) display;
-       (void) display_buffer_flags;
+       (void) byte_buffer;
+       (void) view_settings;
+       (void) display_settings;
 #endif
 }
 
-/*********************** Area-specific functions *************************/
+/*********************** Pixel processor functions *************************/
 
-/* ** Sequencer ** */
-
-void IMB_colormanagement_imbuf_to_sequencer_space(ImBuf *ibuf, int make_float)
+ColormanageProcessor *IMB_colormanagement_display_processor_new(const ColorManagedViewSettings *view_settings,
+                                                                const ColorManagedDisplaySettings *display_settings)
 {
-       (void) make_float;
-
-       if (!ibuf->rect_float) {
-               if (make_float && ibuf->rect) {
-                       /* when converting byte buffer to float in sequencer we need to make float
-                        * buffer be in sequencer's working space, which is currently only doable
-                        * from linear space.
-                        *
-                        */
+       ColormanageProcessor *cm_processor;
 
-                       /*
-                        * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's
-                        */
+       cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
 
-                       ibuf->profile = IB_PROFILE_SRGB;
-                       IMB_float_from_rect(ibuf);
-               }
-               else {
-                       /* if there's only byte buffer in image it's already in compositor's working space,
-                        * nothing to do here
-                        */
+#ifdef WITH_OCIO
+       cm_processor->processor = create_display_buffer_processor(view_settings->view_transform, display_settings->display_device,
+                                                                 view_settings->exposure, view_settings->gamma);
 
-                       return;
-               }
+       if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
+               cm_processor->curve_mapping = curvemapping_copy(view_settings->curve_mapping);
+   &