Skip to content

Commit 1754818

Browse files
committed
- WIP Fixed-function for PQ<->Linear function. Doesn't have the GPU implementation yet and the rest may need tweaks.
Signed-off-by: cuneyt.ozdas <cuneyt.ozdas@autodesk.com>
1 parent 67a26e4 commit 1754818

7 files changed

Lines changed: 225 additions & 50 deletions

File tree

include/OpenColorIO/OpenColorTypes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,8 @@ enum FixedFunctionStyle
486486
FIXED_FUNCTION_XYZ_TO_LUV, ///< CIE XYZ to 1976 CIELUV colour space (D65 white)
487487
FIXED_FUNCTION_ACES_GAMUTMAP_02, ///< ACES 0.2 Gamut clamping algorithm -- NOT IMPLEMENTED YET
488488
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)
489+
FIXED_FUNCTION_ACES_GAMUT_COMP_13, ///< ACES 1.3 Parametric Gamut Compression (expects ACEScg values)
490+
FIXED_FUNCTION_PQ_TO_LINEAR, ///< SMPTE ST 2084:2014 EOTF linearization equation
490491
};
491492

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

src/OpenColorIO/ParseUtils.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ const char * FixedFunctionStyleToString(FixedFunctionStyle style)
364364
case FIXED_FUNCTION_XYZ_TO_xyY: return "XYZ_TO_xyY";
365365
case FIXED_FUNCTION_XYZ_TO_uvY: return "XYZ_TO_uvY";
366366
case FIXED_FUNCTION_XYZ_TO_LUV: return "XYZ_TO_LUV";
367+
case FIXED_FUNCTION_PQ_TO_LINEAR: return "PQ_TO_LINEAR";
367368
case FIXED_FUNCTION_ACES_GAMUTMAP_02:
368369
case FIXED_FUNCTION_ACES_GAMUTMAP_07:
369370
throw Exception("Unimplemented fixed function types: "
@@ -391,6 +392,7 @@ FixedFunctionStyle FixedFunctionStyleFromString(const char * style)
391392
else if(str == "xyz_to_xyy") return FIXED_FUNCTION_XYZ_TO_xyY;
392393
else if(str == "xyz_to_uvy") return FIXED_FUNCTION_XYZ_TO_uvY;
393394
else if(str == "xyz_to_luv") return FIXED_FUNCTION_XYZ_TO_LUV;
395+
else if(str == "pq_to_linear") return FIXED_FUNCTION_PQ_TO_LINEAR;
394396

395397
// Default style is meaningless.
396398
std::stringstream ss;

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpCPU.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,22 @@ class Renderer_LUV_TO_XYZ : public OpCPU
210210
void apply(const void * inImg, void * outImg, long numPixels) const override;
211211
};
212212

213+
class Renderer_PQ_TO_LINEAR : public OpCPU {
214+
public:
215+
Renderer_PQ_TO_LINEAR() = delete;
216+
explicit Renderer_PQ_TO_LINEAR(ConstFixedFunctionOpDataRcPtr &data);
217+
218+
void apply(const void *inImg, void *outImg, long numPixels) const override;
219+
};
220+
221+
class Renderer_LINEAR_TO_PQ : public OpCPU {
222+
public:
223+
Renderer_LINEAR_TO_PQ() = delete;
224+
explicit Renderer_LINEAR_TO_PQ(ConstFixedFunctionOpDataRcPtr &data);
225+
226+
void apply(const void *inImg, void *outImg, long numPixels) const override;
227+
};
228+
213229

214230
///////////////////////////////////////////////////////////////////////////////
215231

@@ -1178,7 +1194,150 @@ void Renderer_LUV_TO_XYZ::apply(const void * inImg, void * outImg, long numPixel
11781194
}
11791195

11801196

1197+
namespace ST_2084
1198+
{
1199+
static constexpr float m1 = float(0.25 * 2610. / 4096.);
1200+
static constexpr float m2 = float(128. * 2523. / 4096.);
1201+
static constexpr float c2 = float(32. * 2413. / 4096.);
1202+
static constexpr float c3 = float(32. * 2392. / 4096.);
1203+
static constexpr float c1 = c3 - c2 + 1.;
1204+
} // ST_2084
1205+
1206+
Renderer_PQ_TO_LINEAR::Renderer_PQ_TO_LINEAR(ConstFixedFunctionOpDataRcPtr & /*data*/)
1207+
: OpCPU()
1208+
{
1209+
}
1210+
1211+
void Renderer_PQ_TO_LINEAR::apply(const void *inImg, void *outImg, long numPixels) const
1212+
{
1213+
// TODO optimize
1214+
using namespace ST_2084;
1215+
const float *in = (const float *)inImg;
1216+
float *out = (float *)outImg;
1217+
1218+
for (long idx = 0; idx < numPixels; ++idx, out += 4, in += 4)
1219+
{
1220+
// (0..1) values will be pass through
1221+
// output values are scaled by 100 to convert nits/10,000 into nits/100
1222+
1223+
// R
1224+
{
1225+
float r = in[0];
1226+
if ((r <= 0.0f) || (r >= 1.0f))
1227+
{
1228+
out[0] = r * 100.0f;
1229+
}
1230+
else
1231+
{
1232+
const float x = std::pow(r, 1.f / m2);
1233+
out[0] = 100.0f * std::pow(std::max(0.f, x - c1) / (c2 - c3 * x), 1.f / m1);
1234+
};
1235+
}
11811236

1237+
// G
1238+
{
1239+
float g = in[1];
1240+
if ((g <= 0.0f) || (g >= 1.0f))
1241+
{
1242+
out[1] = g * 100.0f;
1243+
}
1244+
else
1245+
{
1246+
const float x = std::pow(g, 1.f / m2);
1247+
out[1] = 100.0f * std::pow(std::max(0.f, x - c1) / (c2 - c3 * x), 1.f / m1);
1248+
};
1249+
}
1250+
1251+
// B
1252+
{
1253+
float b = in[2];
1254+
if ((b <= 0.0f) || (b >= 1.0f))
1255+
{
1256+
out[2] = b * 100.0f;
1257+
}
1258+
else
1259+
{
1260+
const float x = std::pow(b, 1.f / m2);
1261+
out[2] = 100.0f * std::pow(std::max(0.f, x - c1) / (c2 - c3 * x), 1.f / m1);
1262+
};
1263+
}
1264+
1265+
// A
1266+
out[3] = in[3];
1267+
}
1268+
}
1269+
1270+
Renderer_LINEAR_TO_PQ::Renderer_LINEAR_TO_PQ(ConstFixedFunctionOpDataRcPtr & /*data*/)
1271+
: OpCPU()
1272+
{
1273+
1274+
}
1275+
1276+
void Renderer_LINEAR_TO_PQ::apply(const void *inImg, void *outImg, long numPixels) const
1277+
{
1278+
using namespace ST_2084;
1279+
const float* in = (const float*)inImg;
1280+
float* out = (float*)outImg;
1281+
1282+
// Input is in nits/100, convert to [0,1], where 1 is 10000 nits.
1283+
1284+
for (long idx = 0; idx < numPixels; ++idx, out += 4, in += 4)
1285+
{
1286+
// R
1287+
{
1288+
float r = 0.01f * in[0];
1289+
if (r < 0.0f || r > 1.0f)
1290+
{
1291+
out[0] = r;
1292+
}
1293+
else
1294+
{
1295+
const float L = std::max(0.0f, r);
1296+
const float y = std::pow(L, m1);
1297+
const float ratpoly = (c1 + c2 * y) / (1.f + c3 * y);
1298+
const float N = std::pow(std::max(0.f, ratpoly), m2);
1299+
out[0] = N;
1300+
}
1301+
}
1302+
1303+
// G
1304+
{
1305+
float g = 0.01f * in[1];
1306+
if (g < 0.0f || g > 1.0f)
1307+
{
1308+
out[1] = g;
1309+
}
1310+
else
1311+
{
1312+
const float L = std::max(0.0f, g);
1313+
const float y = std::pow(L, m1);
1314+
const float ratpoly = (c1 + c2 * y) / (1.f + c3 * y);
1315+
const float N = std::pow(std::max(0.f, ratpoly), m2);
1316+
out[1] = N;
1317+
}
1318+
}
1319+
1320+
// B
1321+
{
1322+
float b = 0.01f * in[2];
1323+
if (b < 0.0f || b > 1.0f)
1324+
{
1325+
out[2] = b;
1326+
}
1327+
else
1328+
{
1329+
const float L = std::max(0.0f, b);
1330+
const float y = std::pow(L, m1);
1331+
const float ratpoly = (c1 + c2 * y) / (1.f + c3 * y);
1332+
const float N = std::pow(std::max(0.f, ratpoly), m2);
1333+
out[2] = N;
1334+
}
1335+
}
1336+
1337+
//A
1338+
out[3] = in[3];
1339+
};
1340+
}
11821341

11831342
///////////////////////////////////////////////////////////////////////////////
11841343

@@ -1278,6 +1437,14 @@ ConstOpCPURcPtr GetFixedFunctionCPURenderer(ConstFixedFunctionOpDataRcPtr & func
12781437
{
12791438
return std::make_shared<Renderer_LUV_TO_XYZ>(func);
12801439
}
1440+
case FixedFunctionOpData::PQ_TO_LINEAR:
1441+
{
1442+
return std::make_shared<Renderer_PQ_TO_LINEAR>(func);
1443+
}
1444+
case FixedFunctionOpData::LINEAR_TO_PQ:
1445+
{
1446+
return std::make_shared<Renderer_LINEAR_TO_PQ>(func);
1447+
}
12811448
}
12821449

12831450
throw Exception("Unsupported FixedFunction style");

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ constexpr char XYZ_TO_uvY_STR[] = "XYZ_TO_uvY";
3939
constexpr char uvY_TO_XYZ_STR[] = "uvY_TO_XYZ";
4040
constexpr char XYZ_TO_LUV_STR[] = "XYZ_TO_LUV";
4141
constexpr char LUV_TO_XYZ_STR[] = "LUV_TO_XYZ";
42+
constexpr char PQ_TO_LINEAR_STR[] = "PQ_TO_LINEAR";
43+
constexpr char LINEAR_TO_PQ_STR[] = "LINEAR_TO_PQ";
4244

4345

4446
// NOTE: Converts the enumeration value to its string representation (i.e. CLF reader).
@@ -94,6 +96,10 @@ const char * FixedFunctionOpData::ConvertStyleToString(Style style, bool detaile
9496
return XYZ_TO_LUV_STR;
9597
case LUV_TO_XYZ:
9698
return LUV_TO_XYZ_STR;
99+
case PQ_TO_LINEAR:
100+
return PQ_TO_LINEAR_STR;
101+
case LINEAR_TO_PQ:
102+
return LINEAR_TO_PQ_STR;
97103
}
98104

99105
std::stringstream ss("Unknown FixedFunction style: ");
@@ -196,6 +202,14 @@ FixedFunctionOpData::Style FixedFunctionOpData::GetStyle(const char * name)
196202
{
197203
return LUV_TO_XYZ;
198204
}
205+
else if (0 == Platform::Strcasecmp(name, PQ_TO_LINEAR_STR))
206+
{
207+
return PQ_TO_LINEAR;
208+
}
209+
else if (0 == Platform::Strcasecmp(name, LINEAR_TO_PQ_STR))
210+
{
211+
return LINEAR_TO_PQ;
212+
}
199213
}
200214

201215
std::string st("Unknown FixedFunction style: ");
@@ -270,6 +284,10 @@ FixedFunctionOpData::Style FixedFunctionOpData::ConvertStyle(FixedFunctionStyle
270284
"FIXED_FUNCTION_ACES_GAMUTMAP_02, "
271285
"FIXED_FUNCTION_ACES_GAMUTMAP_07.");
272286
}
287+
case FIXED_FUNCTION_PQ_TO_LINEAR:
288+
{
289+
return FixedFunctionOpData::PQ_TO_LINEAR;
290+
}
273291
}
274292

275293
std::stringstream ss("Unknown FixedFunction transform style: ");
@@ -326,6 +344,10 @@ FixedFunctionStyle FixedFunctionOpData::ConvertStyle(FixedFunctionOpData::Style
326344
case FixedFunctionOpData::XYZ_TO_LUV:
327345
case FixedFunctionOpData::LUV_TO_XYZ:
328346
return FIXED_FUNCTION_XYZ_TO_LUV;
347+
348+
case FixedFunctionOpData::PQ_TO_LINEAR:
349+
case FixedFunctionOpData::LINEAR_TO_PQ:
350+
return FIXED_FUNCTION_PQ_TO_LINEAR;
329351
}
330352

331353
std::stringstream ss("Unknown FixedFunction style: ");
@@ -584,6 +606,17 @@ void FixedFunctionOpData::invert() noexcept
584606
setStyle(XYZ_TO_LUV);
585607
break;
586608
}
609+
610+
case PQ_TO_LINEAR:
611+
{
612+
setStyle(LINEAR_TO_PQ);
613+
break;
614+
}
615+
case LINEAR_TO_PQ:
616+
{
617+
setStyle(PQ_TO_LINEAR);
618+
break;
619+
}
587620
}
588621

589622
// Note that any existing metadata could become stale at this point but
@@ -614,6 +647,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
614647
case FixedFunctionOpData::XYZ_TO_xyY:
615648
case FixedFunctionOpData::XYZ_TO_uvY:
616649
case FixedFunctionOpData::XYZ_TO_LUV:
650+
case FixedFunctionOpData::PQ_TO_LINEAR:
617651
return TRANSFORM_DIR_FORWARD;
618652

619653
case FixedFunctionOpData::ACES_RED_MOD_03_INV:
@@ -627,6 +661,7 @@ TransformDirection FixedFunctionOpData::getDirection() const noexcept
627661
case FixedFunctionOpData::xyY_TO_XYZ:
628662
case FixedFunctionOpData::uvY_TO_XYZ:
629663
case FixedFunctionOpData::LUV_TO_XYZ:
664+
case FixedFunctionOpData::LINEAR_TO_PQ:
630665
return TRANSFORM_DIR_INVERSE;
631666
}
632667
return TRANSFORM_DIR_FORWARD;

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpData.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class FixedFunctionOpData : public OpData
4747
XYZ_TO_uvY, // CIE XYZ to 1976 u'v' chromaticity coordinates
4848
uvY_TO_XYZ, // Inverse of above
4949
XYZ_TO_LUV, // CIE XYZ to 1976 CIELUV colour space (D65 white)
50-
LUV_TO_XYZ // Inverse of above
50+
LUV_TO_XYZ, // Inverse of above
51+
PQ_TO_LINEAR, // Perceptual Quantizer curve to linear
52+
LINEAR_TO_PQ, // Inverse of above
5153
};
5254

5355
static const char * ConvertStyleToString(Style style, bool detailed);

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,14 @@ void GetFixedFunctionGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
671671
{
672672
Add_LUV_TO_XYZ(shaderCreator, ss);
673673
}
674+
case FixedFunctionOpData::PQ_TO_LINEAR:
675+
{
676+
// TODO: Add function
677+
}
678+
case FixedFunctionOpData::LINEAR_TO_PQ:
679+
{
680+
// TODO: Add function
681+
}
674682
}
675683

676684
ss.dedent();

0 commit comments

Comments
 (0)