Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/releases/_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Releases
.. toctree::
:caption: Upgrading to v2

ocio_2_6
ocio_2_5
ocio_2_4
ocio_2_3
Expand Down
59 changes: 59 additions & 0 deletions docs/releases/ocio_2_6.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
..
SPDX-License-Identifier: CC-BY-4.0
Copyright Contributors to the OpenColorIO Project.


OCIO 2.6 Release
================

Timeline
********

OpenColorIO 2.6 was delivered in September 2026 and is in the VFX Reference Platform for
calendar year 2027.

New Feature Guide
=================

New Fixed Function Transforms
*****************************

For Config Authors
++++++++++++++++++

The following new styles are available for use with FixedFunctionTransforms in config
files with ``ocio_profile_version`` set to 2.6 or higher. They implement a conversion from
a linear RGB space with customizable primaries to the JMh (lightness, colorfulness, hue)
color appearance space used in the ACES 2.0 Output Transforms. The ordering is hue,
colorfulness, lightness, rather than JMh since that is the order already established by
the built-in HSV and HSY Fixed Functions and it conforms to the order expected by the
GradingHueCurveTransform. The scaling is {h/360, M/200, J/100} to allow the resulting
images to be easier to work with in DCCs. It takes the following eight parameters to
describe the primaries and white point of the RGB space:
[ red_x, red_y, green_x, green_y, blue_x, blue_y, white_x, white_y ].

* ``FIXED_FUNCTION_ACES_RGB_TO_HMJ_20``


New Built-in Transforms
***********************

For Config Authors
++++++++++++++++++

In config files with ``ocio_profile_version`` set to 2.6 or higher, config authors may take
advantage of the following new BuiltinTransform style that provides a new look transform
intended for use with the ACES 2.0 Output Transforms (SDR only) that provides a brighter,
higher contrast look that is a more finished/graded look. The brightness is adjusted to be
more appropriate for using ACES 2 Output Transforms outside of cinema or TV where the image
has a brighter surround (such as on a web page or video game).

* ``ACES-LMT - ACES 2.0 DCC Look 1``


Release Notes
=============

For additional details, please see the GitHub release page:

`OCIO 2.6.0 <https://github.com/AcademySoftwareFoundation/OpenColorIO/releases/tag/v2.6.0>`_
1 change: 1 addition & 0 deletions include/OpenColorIO/OpenColorTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ enum FixedFunctionStyle
FIXED_FUNCTION_ACES_RGB_TO_JMH_20, ///< ACES 2.0 RGB to JMh -- EXPERIMENTAL
FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20, ///< ACES 2.0 Tonescale and chroma compression -- EXPERIMENTAL
FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20, ///< ACES 2.0 Gamut compression -- EXPERIMENTAL
FIXED_FUNCTION_ACES_RGB_TO_HMJ_20, ///< ACES 2.0 RGB to HMJ (h/360, M/200, J/100)
FIXED_FUNCTION_RGB_TO_HSY_LIN, ///< RGB to HSY (Hue, Saturation, Luminance) for linear spaces
FIXED_FUNCTION_RGB_TO_HSY_LOG, ///< RGB to HSY (Hue, Saturation, Luma) for log spaces
FIXED_FUNCTION_RGB_TO_HSY_VID, ///< RGB to HSY (Hue, Saturation, Luma) for video spaces
Expand Down
36 changes: 34 additions & 2 deletions src/OpenColorIO/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ static constexpr unsigned LastSupportedMajorVersion = OCIO_VERSION_MAJOR;

// For each major version keep the most recent minor.
static const unsigned int LastSupportedMinorVersion[] = {0, // Version 1
5 // Version 2
6 // Version 2
};

} // namespace
Expand Down Expand Up @@ -5674,6 +5674,27 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
<< blt->getStyle() << "'.";
throw Exception(os.str().c_str());
}
if (m_majorVersion == 2 && m_minorVersion < 5
&& ( 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_REC.1886-REC.709 - MIRROR NEGS")
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_REC.1886-REC.2020 - MIRROR NEGS")
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_G2.2-REC.709 - MIRROR NEGS")
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_sRGB - MIRROR NEGS")
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_G2.6-P3-D65 - MIRROR NEGS") )
)
{
std::ostringstream os;
os << "Only config version 2.5 (or higher) can have BuiltinTransform style '"
<< blt->getStyle() << "'.";
throw Exception(os.str().c_str());
}
if (m_majorVersion == 2 && m_minorVersion < 6
&& 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-LMT - ACES 2.0 DCC Look 1"))
{
std::ostringstream os;
os << "Only config version 2.6 (or higher) can have BuiltinTransform style '"
<< blt->getStyle() << "'.";
throw Exception(os.str().c_str());
}
Comment on lines +5690 to +5697

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not missing it, I think this throw is not exercised in the tests (new fixed function throws are tested though). Do we want to add that too?

}
else if (ConstCDLTransformRcPtr cdl = DynamicPtrCast<const CDLTransform>(transform))
{
Expand Down Expand Up @@ -5770,7 +5791,18 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
ffstyle == FIXED_FUNCTION_RGB_TO_HSY_VID )
{
std::ostringstream ss;
ss << "Only config version 2.5 (or higher) can have FixedFunctionTransform style '"
ss << "Only config version 2.5 (or higher) can have FixedFunctionTransform style '"
<< FixedFunctionStyleToString(ffstyle) << "'.";
throw Exception(ss.str().c_str());
}
}

if (m_majorVersion == 2 && m_minorVersion < 6 )
{
if( ffstyle == FIXED_FUNCTION_ACES_RGB_TO_HMJ_20 )
{
std::ostringstream ss;
ss << "Only config version 2.6 (or higher) can have FixedFunctionTransform style '"
<< FixedFunctionStyleToString(ffstyle) << "'.";
throw Exception(ss.str().c_str());
}
Expand Down
2 changes: 2 additions & 0 deletions src/OpenColorIO/ParseUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ const char * FixedFunctionStyleToString(FixedFunctionStyle style)
case FIXED_FUNCTION_ACES_GAMUT_COMP_13: return "ACES_GamutComp13";
case FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20: return "ACES2_OutputTransform";
case FIXED_FUNCTION_ACES_RGB_TO_JMH_20: return "ACES2_RGB_TO_JMh";
case FIXED_FUNCTION_ACES_RGB_TO_HMJ_20: return "ACES2_RGB_TO_HMJ";
case FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20: return "ACES2_TonescaleCompress";
case FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20: return "ACES2_GamutCompress";
case FIXED_FUNCTION_REC2100_SURROUND: return "REC2100_Surround";
Expand Down Expand Up @@ -400,6 +401,7 @@ FixedFunctionStyle FixedFunctionStyleFromString(const char * style)
else if(str == "aces_gamutcomp13") return FIXED_FUNCTION_ACES_GAMUT_COMP_13;
else if(str == "aces2_outputtransform") return FIXED_FUNCTION_ACES_OUTPUT_TRANSFORM_20;
else if(str == "aces2_rgb_to_jmh") return FIXED_FUNCTION_ACES_RGB_TO_JMH_20;
else if(str == "aces2_rgb_to_hmj") return FIXED_FUNCTION_ACES_RGB_TO_HMJ_20;
else if(str == "aces2_tonescalecompress") return FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20;
else if(str == "aces2_gamutcompress") return FIXED_FUNCTION_ACES_GAMUT_COMPRESS_20;
else if(str == "rec2100_surround") return FIXED_FUNCTION_REC2100_SURROUND;
Expand Down
5 changes: 5 additions & 0 deletions src/OpenColorIO/fileformats/ctf/CTFTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ CTFVersion GetOpMinimumVersion(const ConstOpDataRcPtr & op)
{
minVersion = CTF_PROCESS_LIST_VERSION_2_5;
}
else if ( ff->getStyle() == FixedFunctionOpData::ACES_RGB_TO_HMJ_20
|| ff->getStyle() == FixedFunctionOpData::ACES_HMJ_TO_RGB_20 )
{
minVersion = CTF_PROCESS_LIST_VERSION_2_6;
}
break;
}
case OpData::GradingPrimaryType:
Expand Down
5 changes: 4 additions & 1 deletion src/OpenColorIO/fileformats/ctf/CTFTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,12 @@ static const CTFVersion CTF_PROCESS_LIST_VERSION_2_4 = CTFVersion(2, 4);
// Version 2.5 2025-08 adds the GradingHueCurve.
static const CTFVersion CTF_PROCESS_LIST_VERSION_2_5 = CTFVersion(2, 5);

// Version 2.6 2026-08 adds the FixedFunction FIXED_FUNCTION_ACES_RGB_TO_HMJ_20.
static const CTFVersion CTF_PROCESS_LIST_VERSION_2_6 = CTFVersion(2, 6);

// Add new version before this line
// and do not forget to update the following line.
static const CTFVersion CTF_PROCESS_LIST_VERSION = CTF_PROCESS_LIST_VERSION_2_5;
static const CTFVersion CTF_PROCESS_LIST_VERSION = CTF_PROCESS_LIST_VERSION_2_6;


// Version 1.0 initial Autodesk version for InfoElt.
Expand Down
101 changes: 101 additions & 0 deletions src/OpenColorIO/ops/fixedfunction/FixedFunctionOpCPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,23 @@ class Renderer_ACES_RGB_TO_JMh_20 : public OpCPU
ACES2::JMhParams m_p;
};

class Renderer_ACES_RGB_TO_HMJ_20 : public OpCPU
{
public:
Renderer_ACES_RGB_TO_HMJ_20() = delete;
explicit Renderer_ACES_RGB_TO_HMJ_20(ConstFixedFunctionOpDataRcPtr & data);

void apply(const void * inImg, void * outImg, long numPixels) const override;

private:
void fwd(const void * inImg, void * outImg, long numPixels) const;
void inv(const void * inImg, void * outImg, long numPixels) const;

protected:
bool m_fwd;
ACES2::JMhParams m_p;
};

class Renderer_ACES_TONESCALE_COMPRESS_20 : public OpCPU
{
public:
Expand Down Expand Up @@ -1240,6 +1257,83 @@ void Renderer_ACES_RGB_TO_JMh_20::inv(const void * inImg, void * outImg, long nu
}
}

Renderer_ACES_RGB_TO_HMJ_20::Renderer_ACES_RGB_TO_HMJ_20(ConstFixedFunctionOpDataRcPtr & data)
: OpCPU()
{
m_fwd = FixedFunctionOpData::ACES_RGB_TO_HMJ_20 == data->getStyle();

const float red_x = (float) data->getParams()[0];
const float red_y = (float) data->getParams()[1];
const float green_x = (float) data->getParams()[2];
const float green_y = (float) data->getParams()[3];
const float blue_x = (float) data->getParams()[4];
const float blue_y = (float) data->getParams()[5];
const float white_x = (float) data->getParams()[6];
const float white_y = (float) data->getParams()[7];

const Primaries primaries = {
{red_x , red_y },
{green_x, green_y},
{blue_x , blue_y },
{white_x, white_y}
};

m_p = ACES2::init_JMhParams(primaries);
}

void Renderer_ACES_RGB_TO_HMJ_20::apply(const void * inImg, void * outImg, long numPixels) const
{
if (m_fwd)
{
fwd(inImg, outImg, numPixels);
}
else
{
inv(inImg, outImg, numPixels);
}
}

void Renderer_ACES_RGB_TO_HMJ_20::fwd(const void * inImg, void * outImg, long numPixels) const
{
const float * in = (const float *)inImg;
float * out = (float *)outImg;

for(long idx=0; idx<numPixels; ++idx)
{
const ACES2::f3 JMh = ACES2::RGB_to_JMh({in[0], in[1], in[2]}, m_p);

out[0] = ACES2::to_degrees(JMh[2]) / 360.0f;
out[1] = JMh[1] / 200.0f;
out[2] = JMh[0] / 100.0f;
out[3] = in[3];

in += 4;
out += 4;
}
}

void Renderer_ACES_RGB_TO_HMJ_20::inv(const void * inImg, void * outImg, long numPixels) const
{
const float * in = (const float *)inImg;
float * out = (float *)outImg;

for(long idx=0; idx<numPixels; ++idx)
{
const float normalised_hue = ACES2::from_degrees(in[0] * 360.0f);
const float M = in[1] * 200.0f;
const float J = in[2] * 100.0f;
const ACES2::f3 RGB = ACES2::JMh_to_RGB({J, M, normalised_hue}, m_p);

out[0] = RGB[0];
out[1] = RGB[1];
out[2] = RGB[2];
out[3] = in[3];

in += 4;
out += 4;
}
}

Renderer_ACES_TONESCALE_COMPRESS_20::Renderer_ACES_TONESCALE_COMPRESS_20(ConstFixedFunctionOpDataRcPtr & data)
: OpCPU()
{
Expand Down Expand Up @@ -2497,6 +2591,13 @@ ConstOpCPURcPtr GetFixedFunctionCPURenderer(ConstFixedFunctionOpDataRcPtr & func
return std::make_shared<Renderer_ACES_RGB_TO_JMh_20>(func);
}

case FixedFunctionOpData::ACES_RGB_TO_HMJ_20:
case FixedFunctionOpData::ACES_HMJ_TO_RGB_20:
{
// Sharing same renderer (param will be inverted to handle direction).
return std::make_shared<Renderer_ACES_RGB_TO_HMJ_20>(func);
}

case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_FWD:
case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_INV:
{
Expand Down
38 changes: 37 additions & 1 deletion src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ constexpr char ACES_OUTPUT_TRANSFORM_20_FWD_STR[] = "ACESOutputTransform20Fwd"
constexpr char ACES_OUTPUT_TRANSFORM_20_INV_STR[] = "ACESOutputTransform20Inv";
constexpr char ACES_RGB_TO_JMh_20_STR[] = "RGB_TO_JMh_20";
constexpr char ACES_JMh_TO_RGB_20_STR[] = "JMh_TO_RGB_20";
constexpr char ACES_RGB_TO_HMJ_20_STR[] = "RGB_TO_HMJ_20";
constexpr char ACES_HMJ_TO_RGB_20_STR[] = "HMJ_TO_RGB_20";
constexpr char ACES_TONESCALE_COMPRESS_20_FWD_STR[] = "ToneScaleCompress20Fwd";
constexpr char ACES_TONESCALE_COMPRESS_20_INV_STR[] = "ToneScaleCompress20Inv";
constexpr char ACES_GAMUT_COMPRESS_20_FWD_STR[] = "GamutCompress20Fwd";
Expand Down Expand Up @@ -125,6 +127,10 @@ const char * FixedFunctionOpData::ConvertStyleToString(Style style, bool detaile
return ACES_RGB_TO_JMh_20_STR;
case ACES_JMh_TO_RGB_20:
return ACES_JMh_TO_RGB_20_STR;
case ACES_RGB_TO_HMJ_20:
return ACES_RGB_TO_HMJ_20_STR;
case ACES_HMJ_TO_RGB_20:
return ACES_HMJ_TO_RGB_20_STR;
case ACES_TONESCALE_COMPRESS_20_FWD:
return detailed ? "ACES_ToneScaleCompress20 (Forward)" : ACES_TONESCALE_COMPRESS_20_FWD_STR;
case ACES_TONESCALE_COMPRESS_20_INV:
Expand Down Expand Up @@ -254,6 +260,14 @@ FixedFunctionOpData::Style FixedFunctionOpData::GetStyle(const char * name)
{
return ACES_JMh_TO_RGB_20;
}
else if (0 == Platform::Strcasecmp(name, ACES_RGB_TO_HMJ_20_STR))
{
return ACES_RGB_TO_HMJ_20;
}
else if (0 == Platform::Strcasecmp(name, ACES_HMJ_TO_RGB_20_STR))
{
return ACES_HMJ_TO_RGB_20;
}
else if (0 == Platform::Strcasecmp(name, ACES_TONESCALE_COMPRESS_20_FWD_STR))
{
return ACES_TONESCALE_COMPRESS_20_FWD;
Expand Down Expand Up @@ -415,6 +429,11 @@ FixedFunctionOpData::Style FixedFunctionOpData::ConvertStyle(FixedFunctionStyle
return isForward ? FixedFunctionOpData::ACES_RGB_TO_JMh_20 :
FixedFunctionOpData::ACES_JMh_TO_RGB_20;
}
case FIXED_FUNCTION_ACES_RGB_TO_HMJ_20:
{
return isForward ? FixedFunctionOpData::ACES_RGB_TO_HMJ_20 :
FixedFunctionOpData::ACES_HMJ_TO_RGB_20;
}
case FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20:
{
return isForward ? FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_FWD :
Expand Down Expand Up @@ -528,6 +547,10 @@ FixedFunctionStyle FixedFunctionOpData::ConvertStyle(FixedFunctionOpData::Style
case FixedFunctionOpData::ACES_JMh_TO_RGB_20:
return FIXED_FUNCTION_ACES_RGB_TO_JMH_20;

case FixedFunctionOpData::ACES_RGB_TO_HMJ_20:
case FixedFunctionOpData::ACES_HMJ_TO_RGB_20:
return FIXED_FUNCTION_ACES_RGB_TO_HMJ_20;

case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_FWD:
case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_INV:
return FIXED_FUNCTION_ACES_TONESCALE_COMPRESS_20;
Expand Down Expand Up @@ -668,7 +691,8 @@ void FixedFunctionOpData::validate() const
check_param_bounds("peak_luminance", peak_luminance, 1, 10000);
check_param_no_frac("peak_luminance", peak_luminance);
}
else if (m_style == ACES_RGB_TO_JMh_20 || m_style == ACES_JMh_TO_RGB_20)
else if (m_style == ACES_RGB_TO_JMh_20 || m_style == ACES_JMh_TO_RGB_20 ||
m_style == ACES_RGB_TO_HMJ_20 || m_style == ACES_HMJ_TO_RGB_20)
{
if (m_params.size() != 8)
{
Expand Down Expand Up @@ -939,6 +963,16 @@ void FixedFunctionOpData::invert() noexcept
setStyle(ACES_RGB_TO_JMh_20);
break;
}
case ACES_RGB_TO_HMJ_20:
{
setStyle(ACES_HMJ_TO_RGB_20);
break;
}
case ACES_HMJ_TO_RGB_20:
{
setStyle(ACES_RGB_TO_HMJ_20);
break;
}
case ACES_TONESCALE_COMPRESS_20_FWD:
{
setStyle(ACES_TONESCALE_COMPRESS_20_INV);
Expand Down Expand Up @@ -1107,6 +1141,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
case FixedFunctionOpData::ACES_GAMUT_COMP_13_FWD:
case FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_FWD:
case FixedFunctionOpData::ACES_RGB_TO_JMh_20:
case FixedFunctionOpData::ACES_RGB_TO_HMJ_20:
case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_FWD:
case FixedFunctionOpData::ACES_GAMUT_COMPRESS_20_FWD:
case FixedFunctionOpData::REC2100_SURROUND_FWD:
Expand All @@ -1130,6 +1165,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
case FixedFunctionOpData::ACES_GAMUT_COMP_13_INV:
case FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_INV:
case FixedFunctionOpData::ACES_JMh_TO_RGB_20:
case FixedFunctionOpData::ACES_HMJ_TO_RGB_20:
case FixedFunctionOpData::ACES_TONESCALE_COMPRESS_20_INV:
case FixedFunctionOpData::ACES_GAMUT_COMPRESS_20_INV:
case FixedFunctionOpData::REC2100_SURROUND_INV:
Expand Down
Loading
Loading