From 2c0da4a3db96d4aeeeec1cfba4a0a9f5bf0fa970 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 5 May 2019 13:14:37 +0200 Subject: Color management: add functions to detect scene linear and sRGB color spaces Same as the ones in Cycles, but intended for GPU textures. --- intern/cycles/render/colorspace.cpp | 24 ++++++----- intern/opencolorio/fallback_impl.cc | 19 +++++++++ intern/opencolorio/ocio_capi.cc | 8 ++++ intern/opencolorio/ocio_capi.h | 4 ++ intern/opencolorio/ocio_impl.cc | 83 +++++++++++++++++++++++++++++++++++++ intern/opencolorio/ocio_impl.h | 12 ++++++ 6 files changed, 139 insertions(+), 11 deletions(-) diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp index cbfcf774a15..265a0d90b2a 100644 --- a/intern/cycles/render/colorspace.cpp +++ b/intern/cycles/render/colorspace.cpp @@ -114,11 +114,11 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace, } /* Detect if it matches a simple builtin colorspace. */ - bool is_no_op, is_srgb; - is_builtin_colorspace(colorspace, is_no_op, is_srgb); + bool is_scene_linear, is_srgb; + is_builtin_colorspace(colorspace, is_scene_linear, is_srgb); thread_scoped_lock cache_lock(cache_mutex); - if (is_no_op) { + if (is_scene_linear) { VLOG(1) << "Colorspace " << colorspace.string() << " is no-op"; cached_colorspaces[colorspace] = u_colorspace_raw; return u_colorspace_raw; @@ -154,17 +154,19 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace, } } -void ColorSpaceManager::is_builtin_colorspace(ustring colorspace, bool &is_no_op, bool &is_srgb) +void ColorSpaceManager::is_builtin_colorspace(ustring colorspace, + bool &is_scene_linear, + bool &is_srgb) { #ifdef WITH_OCIO const OCIO::Processor *processor = (const OCIO::Processor *)get_processor(colorspace); if (!processor) { - is_no_op = false; + is_scene_linear = false; is_srgb = false; return; } - is_no_op = true; + is_scene_linear = true; is_srgb = true; for (int i = 0; i < 256; i++) { float v = i / 255.0f; @@ -181,27 +183,27 @@ void ColorSpaceManager::is_builtin_colorspace(ustring colorspace, bool &is_no_op /* Make sure that there is no channel crosstalk. */ if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f || fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) { - is_no_op = false; + is_scene_linear = false; is_srgb = false; break; } /* Make sure that the three primaries combine linearly. */ if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) || !compare_floats(cB[2], cW[2], 1e-6f, 64)) { - is_no_op = false; + is_scene_linear = false; is_srgb = false; break; } /* Make sure that the three channels behave identically. */ if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) { - is_no_op = false; + is_scene_linear = false; is_srgb = false; break; } float out_v = average(make_float3(cW[0], cW[1], cW[2])); if (!compare_floats(v, out_v, 1e-6f, 64)) { - is_no_op = false; + is_scene_linear = false; } if (!compare_floats(color_srgb_to_linear(v), out_v, 1e-6f, 64)) { is_srgb = false; @@ -209,7 +211,7 @@ void ColorSpaceManager::is_builtin_colorspace(ustring colorspace, bool &is_no_op } #else (void)colorspace; - is_no_op = false; + is_scene_linear = false; is_srgb = false; #endif } diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index 91f009b3b57..dbf56136d8a 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -363,6 +363,25 @@ int FallbackImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr * /*cs*/) return 0; } +void FallbackImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr * /*config*/, + OCIO_ConstColorSpaceRcPtr *cs, + bool &is_scene_linear, + bool &is_srgb) +{ + if (cs == COLORSPACE_LINEAR) { + is_scene_linear = true; + is_srgb = false; + } + else if (cs == COLORSPACE_SRGB) { + is_scene_linear = false; + is_srgb = true; + } + else { + is_scene_linear = false; + is_srgb = false; + } +} + void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/) { } diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc index 530d1fb8a27..d259ba73e45 100644 --- a/intern/opencolorio/ocio_capi.cc +++ b/intern/opencolorio/ocio_capi.cc @@ -174,6 +174,14 @@ int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) return impl->colorSpaceIsData(cs); } +void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, + OCIO_ConstColorSpaceRcPtr *cs, + bool *is_scene_linear, + bool *is_srgb) +{ + impl->colorSpaceIsBuiltin(config, cs, *is_scene_linear, *is_srgb); +} + void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { impl->colorSpaceRelease(cs); diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 9af302647a3..f4d7717ba46 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -130,6 +130,10 @@ int OCIO_configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char * int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); +void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, + OCIO_ConstColorSpaceRcPtr *cs, + bool *is_scene_linear, + bool *is_srgb); void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc index 1b2207bfb53..644117e0000 100644 --- a/intern/opencolorio/ocio_impl.cc +++ b/intern/opencolorio/ocio_impl.cc @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -34,6 +35,8 @@ using namespace OCIO_NAMESPACE; #include "MEM_guardedalloc.h" +#include "BLI_math_color.h" + #include "ocio_impl.h" #if !defined(WITH_ASSERT_ABORT) @@ -520,6 +523,86 @@ int OCIOImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) return (*(ConstColorSpaceRcPtr *)cs)->isData(); } +static float compare_floats(float a, float b, float abs_diff, int ulp_diff) +{ + /* Returns true if the absolute difference is smaller than abs_diff (for numbers near zero) + * or their relative difference is less than ulp_diff ULPs. Based on: + * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */ + if (fabsf(a - b) < abs_diff) { + return true; + } + + if ((a < 0.0f) != (b < 0.0f)) { + return false; + } + + return (abs((*(int *)&a) - (*(int *)&b)) < ulp_diff); +} + +void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_, + OCIO_ConstColorSpaceRcPtr *cs_, + bool &is_scene_linear, + bool &is_srgb) +{ + ConstConfigRcPtr *config = (ConstConfigRcPtr *)config_; + ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *)cs_; + ConstProcessorRcPtr processor; + + try { + processor = (*config)->getProcessor((*cs)->getName(), "scene_linear"); + } + catch (Exception &exception) { + OCIO_reportException(exception); + is_scene_linear = false; + is_srgb = false; + return; + } + + is_scene_linear = true; + is_srgb = true; + for (int i = 0; i < 256; i++) { + float v = i / 255.0f; + + float cR[3] = {v, 0, 0}; + float cG[3] = {0, v, 0}; + float cB[3] = {0, 0, v}; + float cW[3] = {v, v, v}; + processor->applyRGB(cR); + processor->applyRGB(cG); + processor->applyRGB(cB); + processor->applyRGB(cW); + + /* Make sure that there is no channel crosstalk. */ + if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f || + fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f) { + is_scene_linear = false; + is_srgb = false; + break; + } + /* Make sure that the three primaries combine linearly. */ + if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) || + !compare_floats(cB[2], cW[2], 1e-6f, 64)) { + is_scene_linear = false; + is_srgb = false; + break; + } + /* Make sure that the three channels behave identically. */ + if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) { + is_scene_linear = false; + is_srgb = false; + break; + } + + float out_v = (cW[0] + cW[1] + cW[2]) * (1.0f / 3.0f); + if (!compare_floats(v, out_v, 1e-6f, 64)) { + is_scene_linear = false; + } + if (!compare_floats(srgb_to_linearrgb(v), out_v, 1e-6f, 64)) { + is_srgb = false; + } + } +} + void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *)cs, ConstColorSpaceRcPtr); diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h index 0952e7e16d0..082aa4a091e 100644 --- a/intern/opencolorio/ocio_impl.h +++ b/intern/opencolorio/ocio_impl.h @@ -44,6 +44,10 @@ class IOCIOImpl { virtual int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs) = 0; virtual int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs) = 0; + virtual void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, + OCIO_ConstColorSpaceRcPtr *cs, + bool &is_scene_linear, + bool &is_srgb) = 0; virtual void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) = 0; @@ -160,6 +164,10 @@ class FallbackImpl : public IOCIOImpl { int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); + void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, + OCIO_ConstColorSpaceRcPtr *cs, + bool &is_scene_linear, + bool &is_srgb); void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); @@ -266,6 +274,10 @@ class OCIOImpl : public IOCIOImpl { int colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs); int colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs); + void colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, + OCIO_ConstColorSpaceRcPtr *cs, + bool &is_scene_linear, + bool &is_srgb); void colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs); -- cgit v1.2.3