Skip to content

Commit 5c80c0b

Browse files
authored
Adsk Contrib - Add DCDM displays and improve HLG OOTF implementation (#2051)
* Add DCDM displays, improve Rec.2100 surround Signed-off-by: Doug Walker <[email protected]> * Fix Linux test Signed-off-by: Doug Walker <[email protected]> * Remove 48 nit scaling Signed-off-by: Doug Walker <[email protected]> * Remove D60 DCDM built-ins Signed-off-by: Doug Walker <[email protected]> * Add version check Signed-off-by: Doug Walker <[email protected]> --------- Signed-off-by: Doug Walker <[email protected]>
1 parent e0666e2 commit 5c80c0b

File tree

6 files changed

+142
-49
lines changed

6 files changed

+142
-49
lines changed

src/OpenColorIO/Config.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5234,6 +5234,8 @@ void Config::Impl::checkVersionConsistency(ConstTransformRcPtr & transform) cons
52345234
if (m_majorVersion == 2 && m_minorVersion < 4
52355235
&& ( 0 == Platform::Strcasecmp(blt->getStyle(), "APPLE_LOG_to_ACES2065-1")
52365236
|| 0 == Platform::Strcasecmp(blt->getStyle(), "CURVE - APPLE_LOG_to_LINEAR")
5237+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_DCDM-D65")
5238+
|| 0 == Platform::Strcasecmp(blt->getStyle(), "DISPLAY - CIE-XYZ-D65_to_ST2084-DCDM-D65")
52375239
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-REC709_2.0")
52385240
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - SDR-100nit-P3-D65_2.0")
52395241
|| 0 == Platform::Strcasecmp(blt->getStyle(), "ACES-OUTPUT - ACES2065-1_to_CIE-XYZ-D65 - HDR-108nit-P3-D65_2.0")

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpCPU.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ class Renderer_REC2100_Surround : public OpCPU
212212

213213
protected:
214214
float m_gamma;
215+
float m_minLum;
215216
};
216217

217218
class Renderer_RGB_TO_HSV : public OpCPU
@@ -1171,7 +1172,11 @@ Renderer_REC2100_Surround::Renderer_REC2100_Surround(ConstFixedFunctionOpDataRcP
11711172
: OpCPU()
11721173
{
11731174
const auto fwd = FixedFunctionOpData::REC2100_SURROUND_FWD == data->getStyle();
1174-
const float gamma = fwd ? (float)data->getParams()[0] : (float)(1. / data->getParams()[0]);
1175+
float gamma = (float)data->getParams()[0];
1176+
1177+
m_minLum = fwd ? 1e-4f : powf(1e-4f, gamma);
1178+
1179+
gamma = fwd ? gamma : 1.f / gamma;
11751180

11761181
m_gamma = gamma - 1.f; // compute Y^gamma / Y
11771182
}
@@ -1187,22 +1192,20 @@ void Renderer_REC2100_Surround::apply(const void * inImg, void * outImg, long nu
11871192
const float grn = in[1];
11881193
const float blu = in[2];
11891194

1195+
// Calculate luminance assuming input is Rec.2100 RGB.
1196+
float Y = 0.2627f * red + 0.6780f * grn + 0.0593f * blu;
1197+
1198+
// Mirror the function around the origin.
1199+
Y = std::abs(Y);
1200+
1201+
// Since the slope may approach infinity as Y approaches 0, limit the min value
1202+
// to avoid gaining up the RGB values (which may not be as close to 0).
1203+
//
11901204
// This threshold needs to be bigger than 1e-10 (used above) to prevent extreme
11911205
// gain in dark colors, yet smaller than 1e-2 to prevent distorting the shape of
11921206
// the HLG EOTF curve. Max gain = 1e-4 ** (0.78-1) = 7.6 for HLG min gamma of 0.78.
1193-
//
1194-
// TODO: Should have forward & reverse versions of this so the threshold can be
1195-
// adjusted correctly for the reverse direction.
1196-
constexpr float minLum = 1e-4f;
1207+
Y = std::max(m_minLum, Y);
11971208

1198-
// Calculate luminance assuming input is Rec.2100 RGB.
1199-
// TODO: Add another parameter to allow using other primaries.
1200-
const float Y = std::max( minLum, ( 0.2627f * red +
1201-
0.6780f * grn +
1202-
0.0593f * blu ) );
1203-
1204-
// TODO: Currently our fast approx. requires SSE registers.
1205-
// Either make this whole routine SSE or make fast scalar pow.
12061209
const float Ypow_over_Y = powf(Y, m_gamma);
12071210

12081211
out[0] = red * Ypow_over_Y;

src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,15 +1663,24 @@ void Add_Surround_10_Fwd_Shader(GpuShaderCreatorRcPtr & shaderCreator, GpuShader
16631663
ss.newLine() << pxl << ".rgb = " << pxl << ".rgb * Ypow_over_Y;";
16641664
}
16651665

1666-
void Add_Surround_Shader(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & ss, float gamma)
1666+
void Add_Rec2100_Surround_Shader(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & ss,
1667+
float gamma, bool isForward)
16671668
{
16681669
const std::string pxl(shaderCreator->getPixelName());
16691670

1670-
// TODO: -- add vector inner product to GPUShaderUtils
1671+
float minLum = 1e-4f;
1672+
if (!isForward)
1673+
{
1674+
minLum = powf(minLum, gamma);
1675+
gamma = 1.f / gamma;
1676+
}
1677+
16711678
ss.newLine() << ss.floatDecl("Y")
1672-
<< " = max( 1e-4, 0.2627 * " << pxl << ".rgb.r + "
1673-
<< "0.6780 * " << pxl << ".rgb.g + "
1674-
<< "0.0593 * " << pxl << ".rgb.b );";
1679+
<< " = 0.2627 * " << pxl << ".rgb.r + "
1680+
<< "0.6780 * " << pxl << ".rgb.g + "
1681+
<< "0.0593 * " << pxl << ".rgb.b;";
1682+
1683+
ss.newLine() << "Y = max( " << minLum << ", abs(Y) );";
16751684

16761685
ss.newLine() << ss.floatDecl("Ypow_over_Y") << " = pow( Y, " << (gamma - 1.f) << ");";
16771686

@@ -1965,12 +1974,14 @@ void GetFixedFunctionGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
19651974
}
19661975
case FixedFunctionOpData::REC2100_SURROUND_FWD:
19671976
{
1968-
Add_Surround_Shader(shaderCreator, ss, (float) func->getParams()[0]);
1977+
Add_Rec2100_Surround_Shader(shaderCreator, ss,
1978+
(float) func->getParams()[0], true);
19691979
break;
19701980
}
19711981
case FixedFunctionOpData::REC2100_SURROUND_INV:
19721982
{
1973-
Add_Surround_Shader(shaderCreator, ss, (float)(1. / func->getParams()[0]));
1983+
Add_Rec2100_Surround_Shader(shaderCreator, ss,
1984+
(float) func->getParams()[0], false);
19741985
break;
19751986
}
19761987
case FixedFunctionOpData::RGB_TO_HSV:

src/OpenColorIO/transforms/builtins/Displays.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,25 @@ void RegisterAll(BuiltinTransformRegistryImpl & registry) noexcept
201201
CIE_XYZ_D65_to_P3_D60_BFD_Functor);
202202
}
203203

204+
{
205+
auto CIE_XYZ_D65_to_DCDM_D65_Functor = [](OpRcPtrVec & ops)
206+
{
207+
const double scale = 48.0 / 52.37;
208+
const double scale4[4] = { scale, scale, scale, 1. };
209+
CreateScaleOp(ops, scale4, TRANSFORM_DIR_FORWARD);
210+
211+
const GammaOpData::Params rgbParams = { 2.6 };
212+
const GammaOpData::Params alphaParams = { 1.0 };
213+
auto gammaData = std::make_shared<GammaOpData>(GammaOpData::BASIC_REV,
214+
rgbParams, rgbParams, rgbParams, alphaParams);
215+
CreateGammaOp(ops, gammaData, TRANSFORM_DIR_FORWARD);
216+
};
217+
218+
registry.addBuiltin("DISPLAY - CIE-XYZ-D65_to_DCDM-D65",
219+
"Convert CIE XYZ (D65 white) to Gamma 2.6 (D65 white in XYZ-E encoding)",
220+
CIE_XYZ_D65_to_DCDM_D65_Functor);
221+
}
222+
204223
{
205224
auto CIE_XYZ_D65_to_DisplayP3_Functor = [](OpRcPtrVec & ops)
206225
{
@@ -285,6 +304,17 @@ void RegisterAll(BuiltinTransformRegistryImpl & registry) noexcept
285304
CIE_XYZ_D65_to_ST2084_P3_D65_Functor);
286305
}
287306

307+
{
308+
auto CIE_XYZ_D65_to_ST2084_DCDM_D65_Functor = [](OpRcPtrVec & ops)
309+
{
310+
ST_2084::GenerateLinearToPQOps(ops);
311+
};
312+
313+
registry.addBuiltin("DISPLAY - CIE-XYZ-D65_to_ST2084-DCDM-D65",
314+
"Convert CIE XYZ (D65 white) to ST-2084 (PQ) (D65 white in XYZ-E encoding)",
315+
CIE_XYZ_D65_to_ST2084_DCDM_D65_Functor);
316+
}
317+
288318
{
289319
auto CIE_XYZ_D65_to_REC2100_HLG_1000nit_Functor = [](OpRcPtrVec & ops)
290320
{

tests/cpu/ops/fixedfunction/FixedFunctionOpCPU_tests.cpp

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -927,44 +927,83 @@ OCIO_ADD_TEST(FixedFunctionOpCPU, aces_gamut_map_20)
927927

928928
OCIO_ADD_TEST(FixedFunctionOpCPU, rec2100_surround)
929929
{
930-
const unsigned num_samples = 4;
930+
const unsigned num_samples = 5;
931931

932932
float input_32f[num_samples*4] = {
933-
0.11f, 0.02f, 0.04f, 0.5f,
934-
0.71f, 0.51f, 0.81f, 1.0f,
935-
0.43f, 0.82f, 0.71f, 0.0f,
936-
-1.0f, -0.001f, 1.2f, 0.0f
933+
8.4e-5f, 2.4e-5f, 1.4e-4f, 0.1f,
934+
0.11f, 0.02f, 0.04f, 0.5f,
935+
0.71f, 0.51f, 0.81f, 1.0f,
936+
0.43f, 0.82f, 0.71f, 0.0f,
937+
-1.00f, -0.001f, 1.2f, 0.0f
937938
};
939+
{
940+
OCIO::FixedFunctionOpData::Params params = { 0.78 };
938941

939-
float input2_32f[num_samples * 4];
940-
memcpy(&input2_32f[0], &input_32f[0], sizeof(float)*num_samples * 4);
942+
float output_32f[num_samples * 4];
943+
memcpy(&output_32f[0], &input_32f[0], sizeof(float)*num_samples * 4);
941944

942-
const float expected_32f[num_samples*4] = {
943-
0.21779590f, 0.03959925f, 0.07919850f, 0.5f,
944-
0.80029451f, 0.57485944f, 0.91301214f, 1.0f,
945-
0.46350446f, 0.88389223f, 0.76532131f, 0.0f,
946-
-7.58577776f, -0.00758577f, 9.10293388f, 0.0f,
947-
};
945+
const float expected_32f[num_samples*4] = {
946+
0.000637205163f, 0.000182058618f, 0.001062008605f, 0.1f,
947+
0.21779590f, 0.03959925f, 0.07919850f, 0.5f,
948+
0.80029451f, 0.57485944f, 0.91301214f, 1.0f,
949+
0.46350446f, 0.88389223f, 0.76532131f, 0.0f,
950+
-1.43735918f, -0.00143735918f, 1.72483102f, 0.0f
951+
};
948952

949-
OCIO::FixedFunctionOpData::Params params = { 0.78 };
950-
OCIO::ConstFixedFunctionOpDataRcPtr funcData
951-
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_FWD,
952-
params);
953+
// Forward transform -- input to expected.
954+
OCIO::ConstFixedFunctionOpDataRcPtr funcData
955+
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_FWD,
956+
params);
953957

954-
ApplyFixedFunction(&input_32f[0], &expected_32f[0], num_samples,
955-
funcData,
956-
1e-7f,
957-
__LINE__);
958+
ApplyFixedFunction(&output_32f[0], &expected_32f[0], num_samples,
959+
funcData,
960+
4e-7f,
961+
__LINE__);
958962

959-
OCIO::FixedFunctionOpData::Params params_inv = { 1 / 0.78 };
960-
OCIO::ConstFixedFunctionOpDataRcPtr funcData2
961-
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_INV,
962-
params_inv);
963+
// Inverse transform -- output back to original.
964+
OCIO::ConstFixedFunctionOpDataRcPtr funcDataInv
965+
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_INV,
966+
params);
963967

964-
ApplyFixedFunction(&input2_32f[0], &expected_32f[0], num_samples,
965-
funcData2,
966-
1e-7f,
967-
__LINE__);
968+
ApplyFixedFunction(&output_32f[0], &input_32f[0], num_samples,
969+
funcDataInv,
970+
3e-7f,
971+
__LINE__);
972+
}
973+
{
974+
OCIO::FixedFunctionOpData::Params params = { 1.2 };
975+
976+
float output_32f[num_samples * 4];
977+
memcpy(&output_32f[0], &input_32f[0], sizeof(float)*num_samples * 4);
978+
979+
const float expected_32f[num_samples*4] = {
980+
1.331310281667e-05f, 3.803743661907e-06f, 2.218850469446e-05f, 0.1f,
981+
0.059115925805f, 0.010748350146f, 0.021496700293f, 0.5f,
982+
0.636785774786f, 0.457409500198f, 0.726473912080f, 1.0f,
983+
0.401647721515f, 0.765932864285f, 0.663185772735f, 0.0f,
984+
-7.190495367684e-01f, -7.190495367684e-04f, 8.628594441221e-01f, 0.0f
985+
};
986+
987+
// Forward transform -- input to expected.
988+
OCIO::ConstFixedFunctionOpDataRcPtr funcData
989+
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_FWD,
990+
params);
991+
992+
ApplyFixedFunction(&output_32f[0], &expected_32f[0], num_samples,
993+
funcData,
994+
2e-7f,
995+
__LINE__);
996+
997+
// Inverse transform -- output back to original.
998+
OCIO::ConstFixedFunctionOpDataRcPtr funcDataInv
999+
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::REC2100_SURROUND_INV,
1000+
params);
1001+
1002+
ApplyFixedFunction(&output_32f[0], &input_32f[0], num_samples,
1003+
funcDataInv,
1004+
2e-7f,
1005+
__LINE__);
1006+
}
9681007
}
9691008

9701009
OCIO_ADD_TEST(FixedFunctionOpCPU, RGB_TO_HSV)

tests/cpu/transforms/BuiltinTransform_tests.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,8 @@ AllValues UnitTestValues
538538
{ { 0.5f, 0.4f, 0.3f }, { 0.896805202281f, 0.627254277624f, 0.608228132100f } } },
539539
{ "DISPLAY - CIE-XYZ-D65_to_G2.6-P3-D60-BFD",
540540
{ { 0.5f, 0.4f, 0.3f }, { 0.892433142142f, 0.627011653770f, 0.608093643982f } } },
541+
{ "DISPLAY - CIE-XYZ-D65_to_DCDM-D65",
542+
{ { 0.5f, 0.4f, 0.3f }, { 0.740738422348f, 0.679816639411f, 0.608609083713f } } },
541543
{ "DISPLAY - CIE-XYZ-D65_to_DisplayP3",
542544
{ { 0.5f, 0.4f, 0.3f }, { 0.882580907776f, 0.581526360743f, 0.5606367050000f } } },
543545

@@ -549,6 +551,8 @@ AllValues UnitTestValues
549551
{ { 0.5f, 0.4f, 0.3f }, { 0.464008302136f, 0.398157119110f, 0.384828370950f } } },
550552
{ "DISPLAY - CIE-XYZ-D65_to_ST2084-P3-D65",
551553
{ { 0.5f, 0.4f, 0.3f }, { 0.479939091128f, 0.392091860770f, 0.384886051856f } } },
554+
{ "DISPLAY - CIE-XYZ-D65_to_ST2084-DCDM-D65",
555+
{ { 0.5f, 0.4f, 0.3f }, { 0.440281573420f, 0.419284117712f, 0.392876186489f } } },
552556
{ "DISPLAY - CIE-XYZ-D65_to_REC.2100-HLG-1000nit",
553557
{ { 0.5f, 0.4f, 0.3f }, { 0.5649694f, 0.4038837f, 0.3751478f } } }
554558
};
@@ -589,4 +593,8 @@ OCIO_ADD_TEST(Builtins, validate)
589593
ValidateBuiltinTransform(name, values.first, values.second, __LINE__);
590594
}
591595
}
596+
597+
// The above checks if a test values is missing, but not if there are test values
598+
// that don't have an associated built-in.
599+
OCIO_CHECK_EQUAL(UnitTestValues.size(), reg->getNumBuiltins());
592600
}

0 commit comments

Comments
 (0)