Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lut-free built-ins #18

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
7 changes: 7 additions & 0 deletions docs/api/python/frozen/pyopencolorio_fixedfunctionstyle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

FIXED_FUNCTION_ACES_GAMUT_COMP_13 : ACES 1.3 Parametric Gamut Compression (expects ACEScg values)

FIXED_FUNCTION_PQ_TO_LINEAR : SMPTE ST 2084:2014 EOTF Linearization Equation

.. py:method:: name() -> str
:property:

Expand Down Expand Up @@ -104,6 +106,11 @@
:value: <FixedFunctionStyle.FIXED_FUNCTION_XYZ_TO_xyY: 7>


.. py:attribute:: FixedFunctionStyle.FIXED_FUNCTION_PQ_TO_LINEAR
:module: PyOpenColorIO
:value: <FixedFunctionStyle.FIXED_FUNCTION_PQ_TO_LINEAR: 13>


.. py:property:: FixedFunctionStyle.value
:module: PyOpenColorIO

3 changes: 2 additions & 1 deletion include/OpenColorIO/OpenColorTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ enum FixedFunctionStyle
FIXED_FUNCTION_XYZ_TO_LUV, ///< CIE XYZ to 1976 CIELUV colour space (D65 white)
FIXED_FUNCTION_ACES_GAMUTMAP_02, ///< ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET
FIXED_FUNCTION_ACES_GAMUTMAP_07, ///< ACES 0.7 Gamut clamping algorithm -- NOT IMPLEMENTED YET
FIXED_FUNCTION_ACES_GAMUT_COMP_13 ///< ACES 1.3 Parametric Gamut Compression (expects ACEScg values)
FIXED_FUNCTION_ACES_GAMUT_COMP_13, ///< ACES 1.3 Parametric Gamut Compression (expects ACEScg values)
FIXED_FUNCTION_PQ_TO_LINEAR, ///< SMPTE ST 2084:2014 EOTF linearization equation
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
};

/// Enumeration of the :cpp:class:`ExposureContrastTransform` transform algorithms.
Expand Down
12 changes: 11 additions & 1 deletion src/OpenColorIO/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5300,17 +5300,27 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
}
else if (ConstFixedFunctionTransformRcPtr ff = DynamicPtrCast<const FixedFunctionTransform>(transform))
{
auto ffstyle = ff->getStyle();
if (m_majorVersion < 2)
{
throw Exception("Only config version 2 (or higher) can have "
"FixedFunctionTransform.");
}

if (m_majorVersion == 2 && m_minorVersion < 1 && ff->getStyle() == FIXED_FUNCTION_ACES_GAMUT_COMP_13)
if (m_majorVersion == 2 && m_minorVersion < 1 && ffstyle == FIXED_FUNCTION_ACES_GAMUT_COMP_13)
{
throw Exception("Only config version 2.1 (or higher) can have "
"FixedFunctionTransform style 'ACES_GAMUT_COMP_13'.");
}

if (m_majorVersion == 2 && m_minorVersion < 4 )
{
if(ffstyle == FIXED_FUNCTION_PQ_TO_LINEAR)
{
throw Exception("Only config version 2.4 (or higher) can have "
"FixedFunctionTransform style 'FIXED_FUNCTION_PQ_TO_LINEAR'.");
}
}
}
else if (DynamicPtrCast<const GradingPrimaryTransform>(transform))
{
Expand Down
2 changes: 2 additions & 0 deletions src/OpenColorIO/ParseUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ const char * FixedFunctionStyleToString(FixedFunctionStyle style)
case FIXED_FUNCTION_XYZ_TO_xyY: return "XYZ_TO_xyY";
case FIXED_FUNCTION_XYZ_TO_uvY: return "XYZ_TO_uvY";
case FIXED_FUNCTION_XYZ_TO_LUV: return "XYZ_TO_LUV";
case FIXED_FUNCTION_PQ_TO_LINEAR: return "PQ_TO_LINEAR";
case FIXED_FUNCTION_ACES_GAMUTMAP_02:
case FIXED_FUNCTION_ACES_GAMUTMAP_07:
throw Exception("Unimplemented fixed function types: "
Expand Down Expand Up @@ -391,6 +392,7 @@ FixedFunctionStyle FixedFunctionStyleFromString(const char * style)
else if(str == "xyz_to_xyy") return FIXED_FUNCTION_XYZ_TO_xyY;
else if(str == "xyz_to_uvy") return FIXED_FUNCTION_XYZ_TO_uvY;
else if(str == "xyz_to_luv") return FIXED_FUNCTION_XYZ_TO_LUV;
else if(str == "pq_to_linear") return FIXED_FUNCTION_PQ_TO_LINEAR;

// Default style is meaningless.
std::stringstream ss;
Expand Down
97 changes: 97 additions & 0 deletions src/OpenColorIO/ops/fixedfunction/FixedFunctionOpCPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,22 @@ class Renderer_LUV_TO_XYZ : public OpCPU
void apply(const void * inImg, void * outImg, long numPixels) const override;
};

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

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

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

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


///////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -1178,7 +1194,78 @@ void Renderer_LUV_TO_XYZ::apply(const void * inImg, void * outImg, long numPixel
}


namespace ST_2084
{
using FLOAT = double; // Temp: used for fast float/double switching for precision evaluation.
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
static constexpr FLOAT m1 = FLOAT(0.25 * 2610. / 4096.);
static constexpr FLOAT m2 = FLOAT(128. * 2523. / 4096.);
static constexpr FLOAT c2 = FLOAT(32. * 2413. / 4096.);
static constexpr FLOAT c3 = FLOAT(32. * 2392. / 4096.);
static constexpr FLOAT c1 = c3 - c2 + 1.;
} // ST_2084

Renderer_PQ_TO_LINEAR::Renderer_PQ_TO_LINEAR(ConstFixedFunctionOpDataRcPtr & /*data*/)
: OpCPU()
{
}

void Renderer_PQ_TO_LINEAR::apply(const void *inImg, void *outImg, long numPixels) const
{
/// TODO: This is a short, proof-of-concept implementation, needs optimization.
doug-walker marked this conversation as resolved.
Show resolved Hide resolved

using namespace ST_2084;
const float *in = (const float *)inImg;
float *out = (float *)outImg;

for (long idx = 0; idx < numPixels; ++idx)
{
// RGB
for (int ch = 0; ch < 3; ++ch)
{
float v = *(in++);
const FLOAT vabs = std::abs(FLOAT(v));
const FLOAT x = std::pow(vabs, FLOAT(1.) / m2);
float nits100 = float(FLOAT(100.0) * std::pow(std::max(FLOAT(0), x - c1) / (c2 - c3 * x), FLOAT(1.) / m1));
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
*(out++) = std::copysign(nits100, v);
}

// Alpha
*(out++) = *(in++);
}
}

Renderer_LINEAR_TO_PQ::Renderer_LINEAR_TO_PQ(ConstFixedFunctionOpDataRcPtr & /*data*/)
: OpCPU()
{

doug-walker marked this conversation as resolved.
Show resolved Hide resolved
}

void Renderer_LINEAR_TO_PQ::apply(const void *inImg, void *outImg, long numPixels) const
{
using namespace ST_2084;
const float* in = (const float*)inImg;
float* out = (float*)outImg;

// TODO: This is a short, proof of concept implementation, needs optimization.

// Input is in nits/100, convert to [0,1], where 1 is 10000 nits.
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
for (long idx = 0; idx < numPixels; ++idx)
{
// RGB
for(int ch = 0; ch < 3; ++ch)
{
float v = *(in++);
const FLOAT L = std::abs(v * FLOAT(0.01));
const FLOAT y = std::pow(L, m1);
const FLOAT ratpoly = (c1 + c2 * y) / (FLOAT(1.) + c3 * y);
const FLOAT N = std::pow(ratpoly, m2);
*(out++) = std::copysign(float(N), v);
}

// Alpha
*(out++) = *(in++);
};
}

///////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -1278,6 +1365,16 @@ ConstOpCPURcPtr GetFixedFunctionCPURenderer(ConstFixedFunctionOpDataRcPtr & func
{
return std::make_shared<Renderer_LUV_TO_XYZ>(func);
}
case FixedFunctionOpData::PQ_TO_LINEAR:
{
// TODO: we may want to implement an SIMD renderer if scalar performance is low.
return std::make_shared<Renderer_PQ_TO_LINEAR>(func);
}
case FixedFunctionOpData::LINEAR_TO_PQ:
{
// TODO: we may want to implement an SIMD renderer if scalar performance is low.
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
return std::make_shared<Renderer_LINEAR_TO_PQ>(func);
}
}

throw Exception("Unsupported FixedFunction style");
Expand Down
36 changes: 36 additions & 0 deletions src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ constexpr char XYZ_TO_uvY_STR[] = "XYZ_TO_uvY";
constexpr char uvY_TO_XYZ_STR[] = "uvY_TO_XYZ";
constexpr char XYZ_TO_LUV_STR[] = "XYZ_TO_LUV";
constexpr char LUV_TO_XYZ_STR[] = "LUV_TO_XYZ";
constexpr char PQ_TO_LINEAR_STR[] = "PQ_TO_LINEAR";
constexpr char LINEAR_TO_PQ_STR[] = "LINEAR_TO_PQ";


// NOTE: Converts the enumeration value to its string representation (i.e. CLF reader).
Expand Down Expand Up @@ -94,6 +96,10 @@ const char * FixedFunctionOpData::ConvertStyleToString(Style style, bool detaile
return XYZ_TO_LUV_STR;
case LUV_TO_XYZ:
return LUV_TO_XYZ_STR;
case PQ_TO_LINEAR:
return PQ_TO_LINEAR_STR;
case LINEAR_TO_PQ:
return LINEAR_TO_PQ_STR;
}

std::stringstream ss("Unknown FixedFunction style: ");
Expand Down Expand Up @@ -196,6 +202,14 @@ FixedFunctionOpData::Style FixedFunctionOpData::GetStyle(const char * name)
{
return LUV_TO_XYZ;
}
else if (0 == Platform::Strcasecmp(name, PQ_TO_LINEAR_STR))
{
return PQ_TO_LINEAR;
}
else if (0 == Platform::Strcasecmp(name, LINEAR_TO_PQ_STR))
{
return LINEAR_TO_PQ;
}
}

std::string st("Unknown FixedFunction style: ");
Expand Down Expand Up @@ -270,6 +284,11 @@ FixedFunctionOpData::Style FixedFunctionOpData::ConvertStyle(FixedFunctionStyle
"FIXED_FUNCTION_ACES_GAMUTMAP_02, "
"FIXED_FUNCTION_ACES_GAMUTMAP_07.");
}
case FIXED_FUNCTION_PQ_TO_LINEAR:
{
return isForward ? FixedFunctionOpData::PQ_TO_LINEAR :
FixedFunctionOpData::LINEAR_TO_PQ;
}
}

std::stringstream ss("Unknown FixedFunction transform style: ");
Expand Down Expand Up @@ -326,6 +345,10 @@ FixedFunctionStyle FixedFunctionOpData::ConvertStyle(FixedFunctionOpData::Style
case FixedFunctionOpData::XYZ_TO_LUV:
case FixedFunctionOpData::LUV_TO_XYZ:
return FIXED_FUNCTION_XYZ_TO_LUV;

case FixedFunctionOpData::PQ_TO_LINEAR:
case FixedFunctionOpData::LINEAR_TO_PQ:
return FIXED_FUNCTION_PQ_TO_LINEAR;
}

std::stringstream ss("Unknown FixedFunction style: ");
Expand Down Expand Up @@ -584,6 +607,17 @@ void FixedFunctionOpData::invert() noexcept
setStyle(XYZ_TO_LUV);
break;
}

case PQ_TO_LINEAR:
{
setStyle(LINEAR_TO_PQ);
break;
}
case LINEAR_TO_PQ:
{
setStyle(PQ_TO_LINEAR);
break;
}
}

// Note that any existing metadata could become stale at this point but
Expand Down Expand Up @@ -614,6 +648,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
case FixedFunctionOpData::XYZ_TO_xyY:
case FixedFunctionOpData::XYZ_TO_uvY:
case FixedFunctionOpData::XYZ_TO_LUV:
case FixedFunctionOpData::PQ_TO_LINEAR:
return TRANSFORM_DIR_FORWARD;

case FixedFunctionOpData::ACES_RED_MOD_03_INV:
Expand All @@ -627,6 +662,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
case FixedFunctionOpData::xyY_TO_XYZ:
case FixedFunctionOpData::uvY_TO_XYZ:
case FixedFunctionOpData::LUV_TO_XYZ:
case FixedFunctionOpData::LINEAR_TO_PQ:
return TRANSFORM_DIR_INVERSE;
}
return TRANSFORM_DIR_FORWARD;
Expand Down
4 changes: 3 additions & 1 deletion src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class FixedFunctionOpData : public OpData
XYZ_TO_uvY, // CIE XYZ to 1976 u'v' chromaticity coordinates
uvY_TO_XYZ, // Inverse of above
XYZ_TO_LUV, // CIE XYZ to 1976 CIELUV colour space (D65 white)
LUV_TO_XYZ // Inverse of above
LUV_TO_XYZ, // Inverse of above
PQ_TO_LINEAR, // Perceptual Quantizer curve to linear
LINEAR_TO_PQ, // Inverse of above
};

static const char * ConvertStyleToString(Style style, bool detailed);
Expand Down
64 changes: 64 additions & 0 deletions src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,59 @@ void Add_LUV_TO_XYZ(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & ss)
ss.newLine() << pxl << ".rgb.g = Y;";
}


namespace
{
namespace ST_2084
{
static constexpr double m1 = 0.25 * 2610. / 4096.;
static constexpr double m2 = 128. * 2523. / 4096.;
static constexpr double c2 = 32. * 2413. / 4096.;
static constexpr double c3 = 32. * 2392. / 4096.;
static constexpr double c1 = c3 - c2 + 1.;
}
} // anonymous

void Add_PQ_TO_LINEAR(GpuShaderCreatorRcPtr& shaderCreator, GpuShaderText& ss)
{
using namespace ST_2084;
const std::string pxl(shaderCreator->getPixelName());

// TODO: this still clamps negative inputs
// sign3 = sign(pxl);
// x = abs(pxl);
// x = max(x, vec3(0.));
// x = pow(x, vec3(1. / m2));
// vec3 v = 1. * pow(max(vec3(0.), x - vec3(c1)) / (vec3(c2) - c3 * x), vec3(1. / m1));

ss.newLine() << ss.float3Decl("sign3") << " = sign(" << pxl << ".rgb);";
ss.newLine() << ss.float3Decl("x") << " = abs(" << pxl << ".rgb);";
ss.newLine() << "x = max(x, " << ss.float3Const(0.0) << ");";
doug-walker marked this conversation as resolved.
Show resolved Hide resolved
ss.newLine() << "x = pow(x, "<< ss.float3Const(1.0 / m2) << ");";
ss.newLine() << pxl << ".rgb = 100. * sign3 * pow(max(" << ss.float3Const(0.0) << ", x - " << ss.float3Const(c1) << ") / ("
<< ss.float3Const(c2) << " - " << c3 << " * x), " << ss.float3Const(1.0 / m1) << ");";
}

void Add_LINEAR_TO_PQ(GpuShaderCreatorRcPtr& shaderCreator, GpuShaderText& ss)
{
using namespace ST_2084;
const std::string pxl(shaderCreator->getPixelName());

// TODO: this still clamps negative inputs
doug-walker marked this conversation as resolved.
Show resolved Hide resolved

// double L = std::max(0., input * 0.01);
// double y = std::pow(L, m1);
// double ratpoly = (c1 + c2 * y) / (1. + c3 * y);
// double N = std::pow(std::max(0., ratpoly), m2);

ss.newLine() << ss.float3Decl("sign3") << " = sign(" << pxl << ".rgb);";
ss.newLine() << ss.float3Decl("L") << " = abs(0.01 * " << pxl << ".rgb);";
ss.newLine() << ss.float3Decl("y") << " = pow(L, " << ss.float3Const(m1) << ");";
ss.newLine() << ss.float3Decl("ratpoly") << " = (" << ss.float3Const(c1) << " + " << c2 << " * y) / ("
<< ss.float3Const(1.0) << " + " << c3 << " * y);";
ss.newLine() << pxl << ".rgb = sign3 * pow(max(" << ss.float3Const(0.0) << ", ratpoly), " << ss.float3Const(m2) << ");"; // Do we need "max" here?
}

void GetFixedFunctionGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ConstFixedFunctionOpDataRcPtr & func)
{
Expand Down Expand Up @@ -670,6 +723,17 @@ void GetFixedFunctionGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
case FixedFunctionOpData::LUV_TO_XYZ:
{
Add_LUV_TO_XYZ(shaderCreator, ss);
break;
}
case FixedFunctionOpData::PQ_TO_LINEAR:
{
Add_PQ_TO_LINEAR(shaderCreator, ss);
break;
}
case FixedFunctionOpData::LINEAR_TO_PQ:
{
Add_LINEAR_TO_PQ(shaderCreator, ss);
break;
}
}

Expand Down
Loading
Loading