Skip to content

Commit e0666e2

Browse files
authored
ACES2 Output Transforms (#1983)
* ACES2 BuiltinTransforms Signed-off-by: Rémi Achard <[email protected]> * Fix NaNs and add bound checking on CPU gamut table sampling Signed-off-by: Rémi Achard <[email protected]> * Use powf instead of pow for consistency Signed-off-by: Rémi Achard <[email protected]> * Remove f suffix for floating-point literals in shaders Signed-off-by: Rémi Achard <[email protected]> * Address PR feedback around unit tests Signed-off-by: Rémi Achard <[email protected]> --------- Signed-off-by: Rémi Achard <[email protected]>
1 parent 77e92a9 commit e0666e2

27 files changed

+5248
-103
lines changed

include/OpenColorIO/OpenColorTypes.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -474,19 +474,23 @@ enum RangeStyle
474474
/// Enumeration of the :cpp:class:`FixedFunctionTransform` transform algorithms.
475475
enum FixedFunctionStyle
476476
{
477-
FIXED_FUNCTION_ACES_RED_MOD_03 = 0, ///< Red modifier (ACES 0.3/0.7)
478-
FIXED_FUNCTION_ACES_RED_MOD_10, ///< Red modifier (ACES 1.0)
479-
FIXED_FUNCTION_ACES_GLOW_03, ///< Glow function (ACES 0.3/0.7)
480-
FIXED_FUNCTION_ACES_GLOW_10, ///< Glow function (ACES 1.0)
481-
FIXED_FUNCTION_ACES_DARK_TO_DIM_10, ///< Dark to dim surround correction (ACES 1.0)
482-
FIXED_FUNCTION_REC2100_SURROUND, ///< Rec.2100 surround correction (takes one double for the gamma param)
483-
FIXED_FUNCTION_RGB_TO_HSV, ///< Classic RGB to HSV function
484-
FIXED_FUNCTION_XYZ_TO_xyY, ///< CIE XYZ to 1931 xy chromaticity coordinates
485-
FIXED_FUNCTION_XYZ_TO_uvY, ///< CIE XYZ to 1976 u'v' chromaticity coordinates
486-
FIXED_FUNCTION_XYZ_TO_LUV, ///< CIE XYZ to 1976 CIELUV colour space (D65 white)
487-
FIXED_FUNCTION_ACES_GAMUTMAP_02, ///< ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET
488-
FIXED_FUNCTION_ACES_GAMUTMAP_07, ///< ACES 0.7 Gamut clamping algorithm -- NOT IMPLEMENTED YET
489-
FIXED_FUNCTION_ACES_GAMUT_COMP_13 ///< ACES 1.3 Parametric Gamut Compression (expects ACEScg values)
477+
FIXED_FUNCTION_ACES_RED_MOD_03 = 0, ///< Red modifier (ACES 0.3/0.7)
478+
FIXED_FUNCTION_ACES_RED_MOD_10, ///< Red modifier (ACES 1.0)
479+
FIXED_FUNCTION_ACES_GLOW_03, ///< Glow function (ACES 0.3/0.7)
480+
FIXED_FUNCTION_ACES_GLOW_10, ///< Glow function (ACES 1.0)
481+
FIXED_FUNCTION_ACES_DARK_TO_DIM_10, ///< Dark to dim surround correction (ACES 1.0)
482+
FIXED_FUNCTION_REC2100_SURROUND, ///< Rec.2100 surround correction (takes one double for the gamma param)
483+
FIXED_FUNCTION_RGB_TO_HSV, ///< Classic RGB to HSV function
484+
FIXED_FUNCTION_XYZ_TO_xyY, ///< CIE XYZ to 1931 xy chromaticity coordinates
485+
FIXED_FUNCTION_XYZ_TO_uvY, ///< CIE XYZ to 1976 u'v' chromaticity coordinates
486+
FIXED_FUNCTION_XYZ_TO_LUV, ///< CIE XYZ to 1976 CIELUV colour space (D65 white)
487+
FIXED_FUNCTION_ACES_GAMUTMAP_02, ///< ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET
488+
FIXED_FUNCTION_ACES_GAMUTMAP_07, ///< ACES 0.7 Gamut clamping algorithm -- NOT IMPLEMENTED YET
489+
FIXED_FUNCTION_ACES_GAMUT_COMP_13, ///< ACES 1.3 Parametric Gamut Compression (expects ACEScg values)
490+
FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20, ///< ACES 2.0 Display Rendering -- EXPERIMENTAL
491+
FIXED_FUNCTION_ACES_RGB_TO_JMH_20, ///< ACES 2.0 RGB to JMh -- EXPERIMENTAL
492+
FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20, ///< ACES 2.0 Tonescale and chroma compression -- EXPERIMENTAL
493+
FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20, ///< ACES 2.0 Gamut compression -- EXPERIMENTAL
490494
};
491495

492496
/// Enumeration of the :cpp:class:`ExposureContrastTransform` transform algorithms.

src/OpenColorIO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ set(SOURCES
8484
ops/exposurecontrast/ExposureContrastOpData.cpp
8585
ops/exposurecontrast/ExposureContrastOpGPU.cpp
8686
ops/exposurecontrast/ExposureContrastOp.cpp
87+
ops/fixedfunction/ACES2/Transform.cpp
8788
ops/fixedfunction/FixedFunctionOpCPU.cpp
8889
ops/fixedfunction/FixedFunctionOpData.cpp
8990
ops/fixedfunction/FixedFunctionOpGPU.cpp

src/OpenColorIO/Config.cpp

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5233,7 +5233,38 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
52335233
}
52345234
if (m_majorVersion == 2 && m_minorVersion < 4
52355235
&& ( 0 == Platform::Strcasecmp(blt->getStyle(), "APPLE_LOG_to_ACES2065-1")
5236-
|| 0 == Platform::Strcasecmp(blt->getStyle(), "CURVE - APPLE_LOG_to_LINEAR") )
5236+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "CURVE - APPLE_LOG_to_LINEAR")
5237+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-REC709_2.0")
5238+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-P3-D65_2.0")
5239+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-108nit-P3-D65_2.0")
5240+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-300nit-P3-D65_2.0")
5241+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-500nit-P3-D65_2.0")
5242+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-P3-D65_2.0")
5243+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-P3-D65_2.0")
5244+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-P3-D65_2.0")
5245+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-500nit-REC2020_2.0")
5246+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-REC2020_2.0")
5247+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-REC2020_2.0")
5248+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-REC2020_2.0")
5249+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-REC709-D60-in-REC709-D65_2.0")
5250+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-REC709-D60-in-P3-D65_2.0")
5251+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-REC709-D60-in-REC2020-D65_2.0")
5252+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-P3-D60-in-P3-D65_2.0")
5253+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-P3-D60-in-XYZ-E_2.0")
5254+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-108nit-P3-D60-in-P3-D65_2.0")
5255+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-300nit-P3-D60-in-XYZ-E_2.0")
5256+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-500nit-P3-D60-in-P3-D65_2.0")
5257+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-P3-D60-in-P3-D65_2.0")
5258+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-P3-D60-in-P3-D65_2.0")
5259+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-P3-D60-in-P3-D65_2.0")
5260+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-500nit-P3-D60-in-REC2020-D65_2.0")
5261+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-P3-D60-in-REC2020-D65_2.0")
5262+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-P3-D60-in-REC2020-D65_2.0")
5263+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-P3-D60-in-REC2020-D65_2.0")
5264+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-500nit-REC2020-D60-in-REC2020-D65_2.0")
5265+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-1000nit-REC2020-D60-in-REC2020-D65_2.0")
5266+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-2000nit-REC2020-D60-in-REC2020-D65_2.0")
5267+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-4000nit-REC2020-D60-in-REC2020-D65_2.0") )
52375268
)
52385269
{
52395270
std::ostringstream os;
@@ -5311,6 +5342,30 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
53115342
throw Exception("Only config version 2.1 (or higher) can have "
53125343
"FixedFunctionTransform style 'ACES_GAMUT_COMP_13'.");
53135344
}
5345+
5346+
if (m_majorVersion == 2 && m_minorVersion < 4 && ff->getStyle() == FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20)
5347+
{
5348+
throw Exception("Only config version 2.4 (or higher) can have "
5349+
"FixedFunctionTransform style 'ACES_OUTPUT_TRANSFORM_20'.");
5350+
}
5351+
5352+
if (m_majorVersion == 2 && m_minorVersion < 4 && ff->getStyle() == FIXED_FUNCTION_ACES_RGB_TO_JMH_20)
5353+
{
5354+
throw Exception("Only config version 2.4 (or higher) can have "
5355+
"FixedFunctionTransform style 'ACES_RGB_TO_JMH_20'.");
5356+
}
5357+
5358+
if (m_majorVersion == 2 && m_minorVersion < 4 && ff->getStyle() == FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20)
5359+
{
5360+
throw Exception("Only config version 2.4 (or higher) can have "
5361+
"FixedFunctionTransform style 'ACES_TONESCALE_COMPRESS_20'.");
5362+
}
5363+
5364+
if (m_majorVersion == 2 && m_minorVersion < 4 && ff->getStyle() == FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20)
5365+
{
5366+
throw Exception("Only config version 2.4 (or higher) can have "
5367+
"FixedFunctionTransform style 'ACES_GAMUT_COMPRESS_20'.");
5368+
}
53145369
}
53155370
else if (DynamicPtrCast<const GradingPrimaryTransform>(transform))
53165371
{

src/OpenColorIO/GpuShaderUtils.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,16 @@ std::string GpuShaderText::intKeywordConst() const
399399
return str;
400400
}
401401

402+
std::string GpuShaderText::intDecl(const std::string & name) const
403+
{
404+
if (name.empty())
405+
{
406+
throw Exception("GPU variable name is empty.");
407+
}
408+
409+
return intKeyword() + " " + name;
410+
}
411+
402412
std::string GpuShaderText::colorDecl(const std::string & name) const
403413
{
404414
if (name.empty())
@@ -617,6 +627,13 @@ std::string GpuShaderText::float2Keyword() const
617627
return getVecKeyword<2>(m_lang);
618628
}
619629

630+
std::string GpuShaderText::float2Const(const std::string& x, const std::string& y) const
631+
{
632+
std::ostringstream kw;
633+
kw << float2Keyword() << "(" << x << ", " << y << ")";
634+
return kw.str();
635+
}
636+
620637
std::string GpuShaderText::float2Decl(const std::string & name) const
621638
{
622639
if (name.empty())
@@ -894,6 +911,72 @@ void GpuShaderText::declareUniformArrayInt(const std::string & uniformName, unsi
894911
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << intKeyword() << " " << uniformName << "[" << size << "];";
895912
}
896913

914+
// Keep the method private as only float & double types are expected
915+
template<typename T>
916+
std::string matrix3Mul(const T * m3x3, const std::string & vecName, GpuLanguage lang)
917+
{
918+
if (vecName.empty())
919+
{
920+
throw Exception("GPU variable name is empty.");
921+
}
922+
923+
std::ostringstream kw;
924+
switch (lang)
925+
{
926+
case GPU_LANGUAGE_GLSL_1_2:
927+
case GPU_LANGUAGE_GLSL_1_3:
928+
case GPU_LANGUAGE_GLSL_4_0:
929+
case GPU_LANGUAGE_GLSL_ES_1_0:
930+
case GPU_LANGUAGE_GLSL_ES_3_0:
931+
{
932+
// OpenGL shader program requests a transposed matrix
933+
kw << "mat3("
934+
<< getMatrixValues<T, 3>(m3x3, lang, true) << ") * " << vecName;
935+
break;
936+
}
937+
case GPU_LANGUAGE_CG:
938+
{
939+
kw << "mul(half3x3("
940+
<< getMatrixValues<T, 3>(m3x3, lang, false) << "), " << vecName << ")";
941+
break;
942+
}
943+
case GPU_LANGUAGE_HLSL_DX11:
944+
{
945+
kw << "mul(" << vecName
946+
<< ", float3x3(" << getMatrixValues<T, 3>(m3x3, lang, true) << "))";
947+
break;
948+
}
949+
case LANGUAGE_OSL_1:
950+
{
951+
kw << "matrix(" << getMatrixValues<T, 3>(m3x3, lang, false) << ") * " << vecName;
952+
break;
953+
}
954+
case GPU_LANGUAGE_MSL_2_0:
955+
{
956+
kw << "float3x3(" << getMatrixValues<T, 3>(m3x3, lang, true) << ") * " << vecName;
957+
break;
958+
}
959+
960+
default:
961+
{
962+
throw Exception("Unknown GPU shader language.");
963+
}
964+
}
965+
return kw.str();
966+
}
967+
968+
std::string GpuShaderText::mat3fMul(const float * m3x3,
969+
const std::string & vecName) const
970+
{
971+
return matrix3Mul<float>(m3x3, vecName, m_lang);
972+
}
973+
974+
std::string GpuShaderText::mat3fMul(const double * m3x3,
975+
const std::string & vecName) const
976+
{
977+
return matrix3Mul<double>(m3x3, vecName, m_lang);
978+
}
979+
897980
// Keep the method private as only float & double types are expected
898981
template<typename T>
899982
std::string matrix4Mul(const T * m4x4, const std::string & vecName, GpuLanguage lang)

src/OpenColorIO/GpuShaderUtils.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class GpuShaderText
7575

7676
std::string intKeyword() const;
7777
std::string intKeywordConst() const;
78+
std::string intDecl(const std::string& name) const;
7879

7980
std::string colorDecl(const std::string& name) const;
8081

@@ -105,6 +106,8 @@ class GpuShaderText
105106
//
106107

107108
std::string float2Keyword() const;
109+
// Get the string for creating constant vector with three elements
110+
std::string float2Const(const std::string& x, const std::string& y) const;
108111
std::string float2Decl(const std::string& name) const;
109112

110113
//
@@ -195,7 +198,11 @@ class GpuShaderText
195198
// Matrix multiplication helpers
196199
//
197200

198-
// Get the string for multiplying a 4x4 matrix and a four-element vector
201+
// Get the string for multiplying a 3x3 matrix and a three-elements vector
202+
std::string mat3fMul(const float * m3x3, const std::string & vecName) const;
203+
std::string mat3fMul(const double * m3x3, const std::string & vecName) const;
204+
205+
// Get the string for multiplying a 4x4 matrix and a four-elements vector
199206
std::string mat4fMul(const float * m4x4, const std::string & vecName) const;
200207
std::string mat4fMul(const double * m4x4, const std::string & vecName) const;
201208

src/OpenColorIO/OCIOYaml.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,14 +1351,28 @@ inline void load(const YAML::Node& node, FixedFunctionTransformRcPtr& t)
13511351
{
13521352
std::vector<double> params;
13531353
load(iter->second, params);
1354-
t->setParams(&params[0], params.size());
1354+
if (!params.empty())
1355+
{
1356+
t->setParams(&params[0], params.size());
1357+
}
13551358
}
13561359
else if(key == "style")
13571360
{
13581361
std::string style;
13591362
load(iter->second, style);
13601363
t->setStyle( FixedFunctionStyleFromString(style.c_str()) );
13611364
styleFound = true;
1365+
1366+
const FixedFunctionStyle styleID = t->getStyle();
1367+
if (styleID == FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20
1368+
|| styleID == FIXED_FUNCTION_ACES_RGB_TO_JMH_20
1369+
|| styleID == FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20
1370+
|| styleID == FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20)
1371+
{
1372+
std::ostringstream os;
1373+
os << "FixedFunction style is experimental and may be removed in a future release: '" << style << "'.";
1374+
LogWarning(os.str());
1375+
}
13621376
}
13631377
else if(key == "direction")
13641378
{
@@ -1393,6 +1407,17 @@ inline void save(YAML::Emitter& out, ConstFixedFunctionTransformRcPtr t)
13931407
out << YAML::Key << "style";
13941408
out << YAML::Value << YAML::Flow << FixedFunctionStyleToString(t->getStyle());
13951409

1410+
const FixedFunctionStyle styleID = t->getStyle();
1411+
if (styleID == FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20
1412+
|| styleID == FIXED_FUNCTION_ACES_RGB_TO_JMH_20
1413+
|| styleID == FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20
1414+
|| styleID == FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20)
1415+
{
1416+
std::ostringstream os;
1417+
os << "FixedFunction style is experimental and may be removed in a future release: '" << FixedFunctionStyleToString(t->getStyle()) << "'.";
1418+
LogWarning(os.str());
1419+
}
1420+
13961421
const size_t numParams = t->getNumParams();
13971422
if(numParams>0)
13981423
{

0 commit comments

Comments
 (0)