Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filmicrgb: add rational function to toe/shoulder #8764

Merged
merged 1 commit into from
Apr 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
113 changes: 91 additions & 22 deletions data/kernels/filmic.cl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ typedef enum dt_iop_filmicrgb_reconstruction_type_t
DT_FILMIC_RECONSTRUCT_RATIOS = 1,
} dt_iop_filmicrgb_reconstruction_type_t;

typedef enum dt_iop_filmicrgb_curve_type_t
{
DT_FILMIC_CURVE_POLY_4 = 0, // $DESCRIPTION: "hard"
DT_FILMIC_CURVE_POLY_3 = 1, // $DESCRIPTION: "soft"
DT_FILMIC_CURVE_RATIONAL = 2, // $DESCRIPTION: "safe"
} dt_iop_filmicrgb_curve_type_t;

kernel void
filmic (read_only image2d_t in, write_only image2d_t out, int width, int height,
const float dynamic_range, const float shadows_range, const float grey,
Expand Down Expand Up @@ -218,14 +225,66 @@ inline float4 linear_saturation(const float4 x, const float luminance, const flo

inline float filmic_spline(const float x,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max)
const float latitude_min, const float latitude_max,
const dt_iop_filmicrgb_curve_type_t type[2])
{
// if type polynomial :
// y = M5 * x⁴ + M4 * x³ + M3 * x² + M2 * x¹ + M1 * x⁰
// but we rewrite it using Horner factorisation, to spare ops and enable FMA in available
// else if type rational :
// y = M1 * (M2 * (x - x_0)² + (x - x_0)) / (M2 * (x - x_0)² + (x - x_0) + M3)

return (x < latitude_min) ? M1.x + x * (M2.x + x * (M3.x + x * (M4.x + x * M5.x))) : // toe
(x > latitude_max) ? M1.y + x * (M2.y + x * (M3.y + x * (M4.y + x * M5.y))) : // shoulder
M1.z + x * (M2.z + x * (M3.z + x * (M4.z + x * M5.z))); // latitude
float result;

if(x < latitude_min)
{
// toe
if(type[0] == DT_FILMIC_CURVE_POLY_4)
{
// polynomial toe, 4th order
result = M1.x + x * (M2.x + x * (M3.x + x * (M4.x + x * M5.x)));
}
else if(type[0] == DT_FILMIC_CURVE_POLY_3)
{
// polynomial toe, 3rd order
result = M1.x + x * (M2.x + x * (M3.x + x * M4.x));
}
else
{
// rational toe
const float xi = latitude_min - x;
const float rat = xi * (xi * M2.x + 1.f);
result = M4.x - M1.x * rat / (rat + M3.x);
}
}
else if(x > latitude_max)
{
// shoulder
if(type[1] == DT_FILMIC_CURVE_POLY_4)
{
// polynomial shoulder, 4th order
result = M1.y + x * (M2.y + x * (M3.y + x * (M4.y + x * M5.y)));
}
else if(type[1] == DT_FILMIC_CURVE_POLY_3)
{
// polynomial shoulder, 3rd order
result = M1.y + x * (M2.y + x * (M3.y + x * M4.y));
}
else
{
// rational toe
const float xi = x - latitude_max;
const float rat = xi * (xi * M2.y + 1.f);
result = M4.y + M1.y * rat / (rat + M3.y);
}
}
else
{
// latitude
result = M1.z + x * M2.z;
}

return result;
}

#define NORM_MIN 1.52587890625e-05f // norm can't be < to 2^(-16)
Expand All @@ -252,7 +311,8 @@ inline float4 filmic_split_v1(const float4 i,
read_only image2d_t lut, const int use_work_profile,
const float sigma_toe, const float sigma_shoulder, const float saturation,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power)
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_curve_type_t type[2])
{
float4 o;

Expand All @@ -272,9 +332,9 @@ inline float4 filmic_split_v1(const float4 i,
o = linear_saturation(o, luminance, desaturation);

// Filmic spline
o.x = filmic_spline(o.x, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.y = filmic_spline(o.y, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.z = filmic_spline(o.z, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.x = filmic_spline(o.x, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);
o.y = filmic_spline(o.y, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);
o.z = filmic_spline(o.z, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);

// Output power
o = native_powr(clamp(o, (float4)0.0f, (float4)1.0f), output_power);
Expand All @@ -288,7 +348,8 @@ inline float4 filmic_split_v2_v3(const float4 i,
read_only image2d_t lut, const int use_work_profile,
const float sigma_toe, const float sigma_shoulder, const float saturation,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power)
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_curve_type_t type[2])
{
float4 o;

Expand All @@ -308,9 +369,9 @@ inline float4 filmic_split_v2_v3(const float4 i,
o = linear_saturation(o, luminance, desaturation);

// Filmic spline
o.x = filmic_spline(o.x, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.y = filmic_spline(o.y, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.z = filmic_spline(o.z, M1, M2, M3, M4, M5, latitude_min, latitude_max);
o.x = filmic_spline(o.x, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);
o.y = filmic_spline(o.y, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);
o.z = filmic_spline(o.z, M1, M2, M3, M4, M5, latitude_min, latitude_max, type);

// Output power
o = native_powr(clamp(o, (float4)0.0f, (float4)1.0f), output_power);
Expand All @@ -327,7 +388,8 @@ filmicrgb_split (read_only image2d_t in, write_only image2d_t out,
const float sigma_toe, const float sigma_shoulder, const float saturation,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_colorscience_type_t color_science)
const dt_iop_filmicrgb_colorscience_type_t color_science,
const dt_iop_filmicrgb_curve_type_t type_1, const dt_iop_filmicrgb_curve_type_t type_2)
{
const unsigned int x = get_global_id(0);
const unsigned int y = get_global_id(1);
Expand All @@ -337,14 +399,16 @@ filmicrgb_split (read_only image2d_t in, write_only image2d_t out,
const float4 i = read_imagef(in, sampleri, (int2)(x, y));
float4 o;

const dt_iop_filmicrgb_curve_type_t type[2] = { type_1, type_2 };

switch(color_science)
{
case DT_FILMIC_COLORSCIENCE_V1:
{
o = filmic_split_v1(i, dynamic_range, black_exposure, grey_value,
profile_info, lut, use_work_profile,
sigma_toe, sigma_shoulder, saturation,
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power);
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power, type);
break;
}
case DT_FILMIC_COLORSCIENCE_V2:
Expand All @@ -353,7 +417,7 @@ filmicrgb_split (read_only image2d_t in, write_only image2d_t out,
o = filmic_split_v2_v3(i, dynamic_range, black_exposure, grey_value,
profile_info, lut, use_work_profile,
sigma_toe, sigma_shoulder, saturation,
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power);
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power, type);
break;
}
}
Expand All @@ -371,7 +435,8 @@ inline float4 filmic_chroma_v1(const float4 i,
const float sigma_toe, const float sigma_shoulder, const float saturation,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_methods_type_t variant)
const dt_iop_filmicrgb_methods_type_t variant,
const dt_iop_filmicrgb_curve_type_t type[2])
{
float norm = fmax(get_pixel_norm(i, variant, profile_info, lut, use_work_profile), NORM_MIN);

Expand All @@ -398,7 +463,7 @@ inline float4 filmic_chroma_v1(const float4 i,

// Filmic S curve on the max RGB
// Apply the transfer function of the display
norm = native_powr(clamp(filmic_spline(norm, M1, M2, M3, M4, M5, latitude_min, latitude_max), 0.0f, 1.0f), output_power);
norm = native_powr(clamp(filmic_spline(norm, M1, M2, M3, M4, M5, latitude_min, latitude_max, type), 0.0f, 1.0f), output_power);

return o * norm;
}
Expand All @@ -412,7 +477,8 @@ inline float4 filmic_chroma_v2_v3(const float4 i,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_methods_type_t variant,
const dt_iop_filmicrgb_colorscience_type_t colorscience_version)
const dt_iop_filmicrgb_colorscience_type_t colorscience_version,
const dt_iop_filmicrgb_curve_type_t type[2])
{
float norm = fmax(get_pixel_norm(i, variant, profile_info, lut, use_work_profile), NORM_MIN);

Expand All @@ -431,7 +497,7 @@ inline float4 filmic_chroma_v2_v3(const float4 i,

// Filmic S curve on the max RGB
// Apply the transfer function of the display
norm = native_powr(clamp(filmic_spline(norm, M1, M2, M3, M4, M5, latitude_min, latitude_max), 0.0f, 1.0f), output_power);
norm = native_powr(clamp(filmic_spline(norm, M1, M2, M3, M4, M5, latitude_min, latitude_max, type), 0.0f, 1.0f), output_power);

// Re-apply ratios with saturation change
ratios = fmax(ratios + ((float4)1.0f - ratios) * ((float4)1.0f - desaturation), (float4)0.f);
Expand Down Expand Up @@ -465,7 +531,8 @@ filmicrgb_chroma (read_only image2d_t in, write_only image2d_t out,
const float4 M1, const float4 M2, const float4 M3, const float4 M4, const float4 M5,
const float latitude_min, const float latitude_max, const float output_power,
const dt_iop_filmicrgb_methods_type_t variant,
const dt_iop_filmicrgb_colorscience_type_t color_science)
const dt_iop_filmicrgb_colorscience_type_t color_science,
const dt_iop_filmicrgb_curve_type_t type_1, const dt_iop_filmicrgb_curve_type_t type_2)
{
const unsigned int x = get_global_id(0);
const unsigned int y = get_global_id(1);
Expand All @@ -475,14 +542,16 @@ filmicrgb_chroma (read_only image2d_t in, write_only image2d_t out,
const float4 i = read_imagef(in, sampleri, (int2)(x, y));
float4 o;

const dt_iop_filmicrgb_curve_type_t type[2] = { type_1, type_2 };

switch(color_science)
{
case DT_FILMIC_COLORSCIENCE_V1:
{
o = filmic_chroma_v1(i, dynamic_range, black_exposure, grey_value,
profile_info, lut, use_work_profile,
sigma_toe, sigma_shoulder, saturation,
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power, variant);
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power, variant, type);
break;
}
case DT_FILMIC_COLORSCIENCE_V2:
Expand All @@ -492,7 +561,7 @@ filmicrgb_chroma (read_only image2d_t in, write_only image2d_t out,
profile_info, lut, use_work_profile,
sigma_toe, sigma_shoulder, saturation,
M1, M2, M3, M4, M5, latitude_min, latitude_max, output_power, variant,
color_science);
color_science, type);
break;
}
}
Expand Down