Skip to content

Commit

Permalink
Add roundtrip unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Rémi Achard <remiachard@gmail.com>
  • Loading branch information
remia committed Sep 5, 2024
1 parent c908592 commit 28fdacc
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 21 deletions.
48 changes: 29 additions & 19 deletions src/OpenColorIO/ops/fixedfunction/ACES2/Transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,16 +254,21 @@ f3 tonescale_chroma_compress_fwd(const f3 &JMh, const JMhParams &p, const ToneSc
const float J_ts = std::copysign(1.f, Y_ts) * 100.f * pow(((400.f * F_L_Y) / (27.13f + F_L_Y)) / p.A_w_J, surround[1] * p.z);

// ChromaCompress
const float nJ = J_ts / pc.limit_J_max;
const float snJ = std::max(0.f, 1.f - nJ);
const float Mnorm = chroma_compress_norm(h, pc.chroma_compress_scale);
const float limit = pow(nJ, pc.model_gamma) * reach_m_from_table(h, pc.reach_m_table) / Mnorm;
float M_cp = M;

float M_cp = M * pow(J_ts / J, pc.model_gamma);
M_cp = M_cp / Mnorm;
M_cp = limit - toe_fwd(limit - M_cp, limit - 0.001f, snJ * pc.sat, sqrt(nJ * nJ + pc.sat_thr));
M_cp = toe_fwd(M_cp, limit, nJ * pc.compr, snJ);
M_cp = M_cp * Mnorm;
if (M != 0.0)
{
const float nJ = J_ts / pc.limit_J_max;
const float snJ = std::max(0.f, 1.f - nJ);
const float Mnorm = chroma_compress_norm(h, pc.chroma_compress_scale);
const float limit = pow(nJ, pc.model_gamma) * reach_m_from_table(h, pc.reach_m_table) / Mnorm;

M_cp = M * pow(J_ts / J, pc.model_gamma);
M_cp = M_cp / Mnorm;
M_cp = limit - toe_fwd(limit - M_cp, limit - 0.001f, snJ * pc.sat, sqrt(nJ * nJ + pc.sat_thr));
M_cp = toe_fwd(M_cp, limit, nJ * pc.compr, snJ);
M_cp = M_cp * Mnorm;
}

return {J_ts, M_cp, h};
}
Expand All @@ -286,16 +291,21 @@ f3 tonescale_chroma_compress_inv(const f3 &JMh, const JMhParams &p, const ToneSc
const float J = std::copysign(1.f, Y) * 100.f * pow(((400.f * F_L_Y) / (27.13f + F_L_Y)) / p.A_w_J, surround[1] * p.z);

// Inverse ChromaCompress
const float nJ = J_ts / pc.limit_J_max;
const float snJ = std::max(0.f, 1.f - nJ);
const float Mnorm = chroma_compress_norm(h, pc.chroma_compress_scale);
const float limit = pow(nJ, pc.model_gamma) * reach_m_from_table(h, pc.reach_m_table) / Mnorm;

float M = M_cp / Mnorm;
M = toe_inv(M, limit, nJ * pc.compr, snJ);
M = limit - toe_inv(limit - M, limit - 0.001f, snJ * pc.sat, sqrt(nJ * nJ + pc.sat_thr));
M = M * Mnorm;
M = M * pow(J_ts / J, -pc.model_gamma);
float M = M_cp;

if (M_cp != 0.0)
{
const float nJ = J_ts / pc.limit_J_max;
const float snJ = std::max(0.f, 1.f - nJ);
const float Mnorm = chroma_compress_norm(h, pc.chroma_compress_scale);
const float limit = pow(nJ, pc.model_gamma) * reach_m_from_table(h, pc.reach_m_table) / Mnorm;

M = M_cp / Mnorm;
M = toe_inv(M, limit, nJ * pc.compr, snJ);
M = limit - toe_inv(limit - M, limit - 0.001f, snJ * pc.sat, sqrt(nJ * nJ + pc.sat_thr));
M = M * Mnorm;
M = M * pow(J_ts / J, -pc.model_gamma);
}

return {J, M, h};
}
Expand Down
22 changes: 20 additions & 2 deletions src/OpenColorIO/ops/fixedfunction/FixedFunctionOpGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,12 @@ void _Add_Tonescale_Compress_Fwd_Shader(
ss.newLine() << ss.floatDecl("J_ts") << " = sign(Y_ts) * 100.f * pow(((400.f * F_L_Y) / (27.13f + F_L_Y)) / " << p.A_w_J << ", " << ACES2::surround[1] << " * " << p.z << ");";

// ChromaCompress
ss.newLine() << ss.floatDecl("M_cp") << " = M;";

ss.newLine() << "if (M != 0.0f)";
ss.newLine() << "{";
ss.indent();

ss.newLine() << ss.floatDecl("nJ") << " = J_ts / " << c.limit_J_max << ";";
ss.newLine() << ss.floatDecl("snJ") << " = max(0.f, 1.f - nJ);";

Expand All @@ -584,13 +590,16 @@ void _Add_Tonescale_Compress_Fwd_Shader(

ss.newLine() << ss.floatDecl("reachM") << " = " << reachName << "_sample(h);";
ss.newLine() << ss.floatDecl("limit") << " = pow(nJ, " << c.model_gamma << ") * reachM / Mnorm;";
ss.newLine() << ss.floatDecl("M_cp") << " = M * pow(J_ts / J, " << c.model_gamma << ");";
ss.newLine() << "M_cp = M * pow(J_ts / J, " << c.model_gamma << ");";
ss.newLine() << "M_cp = M_cp / Mnorm;";

ss.newLine() << "M_cp = limit - " << toeName << "(limit - M_cp, limit - 0.001f, snJ * " << c.sat << ", sqrt(nJ * nJ + " << c.sat_thr << "));";
ss.newLine() << "M_cp = " << toeName << "(M_cp, limit, nJ * " << c.compr << ", snJ);";
ss.newLine() << "M_cp = M_cp * Mnorm;";

ss.dedent();
ss.newLine() << "}";

ss.newLine() << pxl << ".rgb = " << ss.float3Const("J_ts", "M_cp", "h") << ";";
}

Expand Down Expand Up @@ -623,6 +632,12 @@ void _Add_Tonescale_Compress_Inv_Shader(
ss.newLine() << ss.floatDecl("J") << " = sign(Y) * 100.f * pow(((400.f * F_L_Y) / (27.13f + F_L_Y)) / " << p.A_w_J << ", " << ACES2::surround[1] << " * " << p.z << ");";

// ChromaCompress
ss.newLine() << ss.floatDecl("M") << " = M_cp;";

ss.newLine() << "if (M_cp != 0.0f)";
ss.newLine() << "{";
ss.indent();

ss.newLine() << ss.floatDecl("nJ") << " = J_ts / " << c.limit_J_max << ";";
ss.newLine() << ss.floatDecl("snJ") << " = max(0.f, 1.f - nJ);";

Expand All @@ -648,12 +663,15 @@ void _Add_Tonescale_Compress_Inv_Shader(
ss.newLine() << ss.floatDecl("reachM") << " = " << reachName << "_sample(h);";
ss.newLine() << ss.floatDecl("limit") << " = pow(nJ, " << c.model_gamma << ") * reachM / Mnorm;";

ss.newLine() << ss.floatDecl("M") << " = M_cp / Mnorm;";
ss.newLine() << "M = M_cp / Mnorm;";
ss.newLine() << "M = " << toeName << "(M, limit, nJ * " << c.compr << ", snJ);";
ss.newLine() << "M = limit - " << toeName << "(limit - M, limit - 0.001f, snJ * " << c.sat << ", sqrt(nJ * nJ + " << c.sat_thr << "));";
ss.newLine() << "M = M * Mnorm;";
ss.newLine() << "M = M * pow(J_ts / J, " << -c.model_gamma << ");";

ss.dedent();
ss.newLine() << "}";

ss.newLine() << pxl << ".rgb = " << ss.float3Const("J", "M", "h") << ";";
}

Expand Down
106 changes: 106 additions & 0 deletions tests/cpu/ops/fixedfunction/FixedFunctionOpCPU_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "testutils/UnitTest.h"
#include "UnitTestUtils.h"
#include "ops/lut3d/Lut3DOp.h"

namespace OCIO = OCIO_NAMESPACE;

Expand Down Expand Up @@ -525,6 +526,111 @@ OCIO_ADD_TEST(FixedFunctionOpCPU, aces_output_transform_20)
__LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_rec709_100n_rt)
{
const int lut_size = 8;
const int num_channels = 4;
int num_samples = lut_size * lut_size * lut_size;
std::vector<float> input_32f(num_samples * num_channels, 0.f);
std::vector<float> output_32f(num_samples * num_channels, 0.f);

GenerateIdentityLut3D(input_32f.data(), lut_size, num_channels, OCIO::LUT3DORDER_FAST_RED);

OCIO::FixedFunctionOpData::Params params = {
// Peak luminance
100.f,
// Rec709 gamut
0.6400, 0.3300, 0.3000, 0.6000, 0.1500, 0.0600, 0.3127, 0.3290
};

OCIO::ConstFixedFunctionOpDataRcPtr funcData
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_INV,
params);

OCIO::ConstOpCPURcPtr op;
OCIO_CHECK_NO_THROW(op = OCIO::GetFixedFunctionCPURenderer(funcData));
OCIO_CHECK_NO_THROW(op->apply(&input_32f[0], &output_32f[0], num_samples));

OCIO::ConstFixedFunctionOpDataRcPtr funcData2
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_FWD,
params);

ApplyFixedFunction(&output_32f[0], &input_32f[0], num_samples,
funcData2,
1e-3f,
__LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_p3d65_100n_rt)
{
const int lut_size = 8;
const int num_channels = 4;
int num_samples = lut_size * lut_size * lut_size;
std::vector<float> input_32f(num_samples * num_channels, 0.f);
std::vector<float> output_32f(num_samples * num_channels, 0.f);

GenerateIdentityLut3D(input_32f.data(), lut_size, num_channels, OCIO::LUT3DORDER_FAST_RED);

OCIO::FixedFunctionOpData::Params params = {
// Peak luminance
100.f,
// P3D65 gamut
0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290
};

OCIO::ConstFixedFunctionOpDataRcPtr funcData
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_INV,
params);

OCIO::ConstOpCPURcPtr op;
OCIO_CHECK_NO_THROW(op = OCIO::GetFixedFunctionCPURenderer(funcData));
OCIO_CHECK_NO_THROW(op->apply(&input_32f[0], &output_32f[0], num_samples));

OCIO::ConstFixedFunctionOpDataRcPtr funcData2
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_FWD,
params);

ApplyFixedFunction(&output_32f[0], &input_32f[0], num_samples,
funcData2,
1e-2f,
__LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_p3d65_1000n_rt)
{
const int lut_size = 8;
const int num_channels = 4;
int num_samples = lut_size * lut_size * lut_size;
std::vector<float> input_32f(num_samples * num_channels, 0.f);
std::vector<float> output_32f(num_samples * num_channels, 0.f);

GenerateIdentityLut3D(input_32f.data(), lut_size, num_channels, OCIO::LUT3DORDER_FAST_RED);

OCIO::FixedFunctionOpData::Params params = {
// Peak luminance
1000.f,
// P3D65 gamut
0.680, 0.320, 0.265, 0.690, 0.150, 0.060, 0.3127, 0.3290
};

OCIO::ConstFixedFunctionOpDataRcPtr funcData
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_INV,
params);

OCIO::ConstOpCPURcPtr op;
OCIO_CHECK_NO_THROW(op = OCIO::GetFixedFunctionCPURenderer(funcData));
OCIO_CHECK_NO_THROW(op->apply(&input_32f[0], &output_32f[0], num_samples));

OCIO::ConstFixedFunctionOpDataRcPtr funcData2
= std::make_shared<OCIO::FixedFunctionOpData>(OCIO::FixedFunctionOpData::ACES_OUTPUT_TRANSFORM_20_FWD,
params);

ApplyFixedFunction(&output_32f[0], &input_32f[0], num_samples,
funcData2,
1e-3f,
__LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_rgb_to_jmh_20)
{
const unsigned num_samples = 27;
Expand Down

0 comments on commit 28fdacc

Please sign in to comment.