@@ -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" );
0 commit comments