Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 4 additions & 3 deletions src/OpenColorIO/ops/fixedfunction/ACES2/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ inline float from_radians(const float v) { return wrap_to_hue_limit(v); };

struct TableBase
{
static constexpr unsigned int _TABLE_ADDITION_ENTRIES = 2;
static constexpr unsigned int base_index = 1;
static constexpr unsigned int _TABLE_ADDITION_LOWER_ENTRIES = 1;
static constexpr unsigned int _TABLE_ADDITION_UPPER_ENTRIES = 2;
static constexpr unsigned int base_index = _TABLE_ADDITION_LOWER_ENTRIES;
static constexpr unsigned int nominal_size = 360;
static constexpr unsigned int total_size = nominal_size + _TABLE_ADDITION_ENTRIES;
static constexpr unsigned int total_size = nominal_size + _TABLE_ADDITION_LOWER_ENTRIES + _TABLE_ADDITION_UPPER_ENTRIES;

static constexpr unsigned int lower_wrap_index = 0;
static constexpr unsigned int upper_wrap_index = base_index + nominal_size;
Expand Down
30 changes: 18 additions & 12 deletions src/OpenColorIO/ops/fixedfunction/ACES2/Transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,9 @@ void build_hue_table(Table1D &hue_table, const std::array<float, max_sorted_corn
// BUG: could break if we are unlucky with samples all being used up by this point
build_hue_sample_interval(hue_table.nominal_size - total_samples, sorted_hues[i - 1], hue_limit, hue_table, total_samples + 1);

hue_table[hue_table.lower_wrap_index] = hue_table[hue_table.last_nominal_index] - hue_limit;
hue_table[hue_table.upper_wrap_index] = hue_table[hue_table.first_nominal_index] + hue_limit;
hue_table[hue_table.lower_wrap_index] = hue_table[hue_table.last_nominal_index] - hue_limit;
hue_table[hue_table.upper_wrap_index] = hue_table[hue_table.first_nominal_index] + hue_limit;
hue_table[hue_table.upper_wrap_index + 1] = hue_table[hue_table.first_nominal_index + 1] + hue_limit;
}

std::array<float, 2> find_display_cusp_for_hue(float hue, const std::array<f3, totalCornerCount>& RGB_corners, const std::array<f3, totalCornerCount>& JMh_corners,
Expand Down Expand Up @@ -820,12 +821,15 @@ Table3D build_cusp_table(const Table1D& hue_table, const std::array<f3, totalCor
}

// Copy extra entries to ease the code to handle hues wrapping around
output_table[output_table.lower_wrap_index][0] = output_table[output_table.last_nominal_index][0];
output_table[output_table.lower_wrap_index][1] = output_table[output_table.last_nominal_index][1];
output_table[output_table.lower_wrap_index][2] = hue_table[hue_table.lower_wrap_index];
output_table[output_table.upper_wrap_index][0] = output_table[output_table.first_nominal_index][0];
output_table[output_table.upper_wrap_index][1] = output_table[output_table.first_nominal_index][1];
output_table[output_table.upper_wrap_index][2] = hue_table[hue_table.upper_wrap_index];
output_table[output_table.lower_wrap_index][0] = output_table[output_table.last_nominal_index][0];
output_table[output_table.lower_wrap_index][1] = output_table[output_table.last_nominal_index][1];
output_table[output_table.lower_wrap_index][2] = hue_table[hue_table.lower_wrap_index];
output_table[output_table.upper_wrap_index][0] = output_table[output_table.first_nominal_index][0];
output_table[output_table.upper_wrap_index][1] = output_table[output_table.first_nominal_index][1];
output_table[output_table.upper_wrap_index][2] = hue_table[hue_table.upper_wrap_index];
output_table[output_table.upper_wrap_index + 1][0] = output_table[output_table.first_nominal_index + 1][0];
output_table[output_table.upper_wrap_index + 1][1] = output_table[output_table.first_nominal_index + 1][1];
output_table[output_table.upper_wrap_index + 1][2] = hue_table[hue_table.upper_wrap_index + 1];
return output_table;
}

Expand Down Expand Up @@ -898,8 +902,9 @@ Table1D make_reach_m_table(const JMhParams &params, const float limit_J_max)

gamutReachTable[i + gamutReachTable.base_index] = high;
}
gamutReachTable[gamutReachTable.lower_wrap_index] = gamutReachTable[gamutReachTable.last_nominal_index];
gamutReachTable[gamutReachTable.upper_wrap_index] = gamutReachTable[gamutReachTable.first_nominal_index];
gamutReachTable[gamutReachTable.lower_wrap_index] = gamutReachTable[gamutReachTable.last_nominal_index];
gamutReachTable[gamutReachTable.upper_wrap_index] = gamutReachTable[gamutReachTable.first_nominal_index];
gamutReachTable[gamutReachTable.upper_wrap_index + 1] = gamutReachTable[gamutReachTable.first_nominal_index + 1];

return gamutReachTable;
}
Expand Down Expand Up @@ -1252,8 +1257,9 @@ void make_upper_hull_gamma(
}

// Copy last populated entries to empty spot 'wrapping' entries
gamutCuspTable[gamutCuspTable.lower_wrap_index][2] = gamutCuspTable[gamutCuspTable.last_nominal_index][2];
gamutCuspTable[gamutCuspTable.upper_wrap_index][2] = gamutCuspTable[gamutCuspTable.first_nominal_index][2];
gamutCuspTable[gamutCuspTable.lower_wrap_index][2] = gamutCuspTable[gamutCuspTable.last_nominal_index][2];
gamutCuspTable[gamutCuspTable.upper_wrap_index][2] = gamutCuspTable[gamutCuspTable.first_nominal_index][2];
gamutCuspTable[gamutCuspTable.upper_wrap_index + 1][2] = gamutCuspTable[gamutCuspTable.first_nominal_index + 1][2];
}

// Tonescale pre-calculations
Expand Down
31 changes: 31 additions & 0 deletions tests/cpu/ops/fixedfunction/FixedFunctionOpCPU_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,37 @@ OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_rec709_100n_rt)
__LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_edge_cases)
{
constexpr int test_cases = 2;
constexpr int num_channels = 4;
std::array<float, test_cases * num_channels> input_32f = {
0.0f, 0.0f, 0.0f, 1.0f,
0.742242277f, 0.0931933373f, 0.321542144f, 1.0f // Bug #2220: related to hue angle calculation
// triggering an out of bounds access in the tables
// at exactly 360 degrees
};
constexpr std::array<float, test_cases * num_channels> expected_32f = {
0.0f, 0.0f, 0.0f, 1.0f,
0.74736571311951f, -0.0019352473318577f, 0.19451357424259f, 1.0f, // Note: exact output value is not
// significant to the test as the bug
// was in the internal table access logic
};

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_FWD,
params);

ApplyFixedFunction(input_32f.data(), expected_32f.data(), test_cases, funcData, 1e-4f, __LINE__);
}

OCIO_ADD_TEST(FixedFunctionOpCPU, aces_ot_20_p3d65_100n_rt)
{
const int lut_size = 8;
Expand Down