96#define INVERSE_SQRT_3 0.5773502691896258f
109#define FILMIC_RECONSTRUCT_DEPRECATED 16.0f
110#define SAFETY_MARGIN 0.01f
112#define DT_GUI_CURVE_EDITOR_INSET DT_PIXEL_APPLY_DPI(1)
429 return _(
"tone mapping|curve|view transform|contrast|saturation|highlights");
435 "for display on SDR screens and paper prints\n"
436 "while preventing clipping in non-destructive ways"),
437 _(
"corrective and creative"),
438 _(
"linear or non-linear, RGB, scene-referred"),
439 _(
"non-linear, RGB"),
440 _(
"non-linear, RGB, display-referred"));
503 geometry->grey_display = powf(CLAMP(
p->grey_point_target,
p->black_point_target,
p->white_point_target) / 100.0f,
504 1.0f /
p->output_power);
506 geometry->grey_display = powf(0.1845f, 1.0f /
p->output_power);
508 const float dynamic_range =
p->white_point_source -
p->black_point_source;
509 geometry->grey_log = fabsf(
p->black_point_source) / dynamic_range;
510 geometry->black_display = powf(CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f,
511 1.0f /
p->output_power);
512 geometry->white_display = powf(fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f,
513 1.0f /
p->output_power);
515 const float slope =
p->contrast * dynamic_range / 8.0f;
516 float min_contrast = 1.0f;
517 min_contrast = fmaxf(min_contrast,
519 min_contrast = fmaxf(min_contrast,
523 geometry->contrast = slope / (
p->output_power * powf(
geometry->grey_display,
p->output_power - 1.0f));
524 const float clamped_contrast = CLAMP(
geometry->contrast, min_contrast, 100.0f);
526 geometry->contrast = clamped_contrast;
548 const float latitude = CLAMP(
p->latitude, 0.0f, 100.0f) / 100.0f;
549 const float balance = CLAMP(
p->balance, -50.0f, 50.0f) / 100.0f;
558 const float balance_correction = (balance > 0.0f)
561 nodes->
toe_log -= balance_correction;
572 float *
const toe,
float *
const shoulder)
578 *toe = CLAMP(
p->latitude, 0.0f, 100.0f);
579 *shoulder = CLAMP(
p->latitude, 0.0f, 100.0f);
584 const float shoulder_span = fmaxf(
geometry.xmax -
geometry.grey_log, 1e-6f);
585 *toe = CLAMP((
geometry.grey_log - nodes.
toe_log) / toe_span, 0.0f, 1.0f) * 100.0f;
586 *shoulder = CLAMP((nodes.
shoulder_log -
geometry.grey_log) / shoulder_span, 0.0f, 1.0f) * 100.0f;
590 const float toe,
const float shoulder,
591 float *
const latitude,
float *
const balance)
596 *latitude =
p->latitude;
597 *balance =
p->balance;
601 const float toe_value = CLAMP(toe, 0.0f, 100.0f) / 100.0f;
602 const float shoulder_value = CLAMP(shoulder, 0.0f, 100.0f) / 100.0f;
604 const float shoulder_span = fmaxf(
geometry.xmax -
geometry.grey_log, 1e-6f);
605 const float latitude_value = CLAMP((toe_span * toe_value + shoulder_span * shoulder_value)
606 / (toe_span + shoulder_span),
609 float balance_value = 0.0f;
610 if(latitude_value > 1e-6f)
612 if(toe_value > shoulder_value)
613 balance_value = 0.5f * (1.0f - shoulder_value / latitude_value);
614 else if(shoulder_value > toe_value)
615 balance_value = 0.5f * (toe_value / latitude_value - 1.0f);
618 *latitude = latitude_value * 100.0f;
619 *balance = CLAMP(balance_value, -0.5f, 0.5f) * 100.0f;
632 float grey_log = spline.
x[2];
633 float toe_log = fminf(spline.
x[1], grey_log);
634 float shoulder_log = fmaxf(spline.
x[3], grey_log);
635 float black_display = spline.
y[0];
636 float grey_display = spline.
y[2];
637 float white_display = spline.
y[4];
638 const float scaled_safety_margin =
SAFETY_MARGIN * (white_display - black_display);
639 float toe_display = fminf(spline.
y[1], grey_display);
640 float shoulder_display = fmaxf(spline.
y[3], grey_display);
642 float hardness =
n->output_power;
643 float contrast = (shoulder_display - toe_display) / (shoulder_log - toe_log);
645 float linear_intercept = grey_display - (contrast * grey_log);
646 if(toe_display < black_display + scaled_safety_margin)
648 toe_display = black_display + scaled_safety_margin;
650 toe_log = (toe_display - linear_intercept) / contrast;
652 if(shoulder_display > white_display - scaled_safety_margin)
654 shoulder_display = white_display - scaled_safety_margin;
656 shoulder_log = (shoulder_display - linear_intercept) / contrast;
659 contrast *= 8.0f / (
n->white_point_source -
n->black_point_source);
660 contrast *= hardness * powf(grey_display, hardness-1.0f);
662 const float latitude = CLAMP((shoulder_display - toe_display) / ((white_display - black_display) - 2.0f * scaled_safety_margin), 0.0f, 0.99f);
664 float toe_display_ref = latitude * (black_display + scaled_safety_margin) + (1.0f - latitude) * grey_display;
665 float shoulder_display_ref = latitude * (white_display - scaled_safety_margin) + (1.0f - latitude) * grey_display;
667 if(shoulder_display < shoulder_display_ref)
668 balance = 0.5f * (1.0f - fmaxf(shoulder_display - grey_display, 0.0f) / fmaxf(shoulder_display_ref - grey_display, 1E-5f));
670 balance = -0.5f * (1.0f - fmaxf(grey_display - toe_display, 0.0f) / fmaxf(grey_display - toe_display_ref, 1E-5f));
677 n->black_point_target = powf(black_display, hardness) * 100.0f;
678 n->white_point_target = powf(white_display, hardness) * 100.0f;
680 n->latitude = latitude * 100.0f;
681 n->contrast = contrast;
682 n->balance = balance * 100.0f;
687 const int new_version)
689 if(old_version == 1 && new_version == 5)
691 typedef struct dt_iop_filmicrgb_params_v1_t
693 float grey_point_source;
694 float black_point_source;
695 float white_point_source;
696 float security_factor;
697 float grey_point_target;
698 float black_point_target;
699 float white_point_target;
706 } dt_iop_filmicrgb_params_v1_t;
708 dt_iop_filmicrgb_params_v1_t *o = (dt_iop_filmicrgb_params_v1_t *)old_params;
714 n->grey_point_source = o->grey_point_source;
715 n->white_point_source = o->white_point_source;
716 n->black_point_source = o->black_point_source;
717 n->security_factor = o->security_factor;
718 n->grey_point_target = o->grey_point_target;
719 n->black_point_target = o->black_point_target;
720 n->white_point_target = o->white_point_target;
721 n->output_power = o->output_power;
722 n->latitude = o->latitude;
723 n->contrast = o->contrast;
724 n->saturation = o->saturation;
725 n->balance = o->balance;
726 n->preserve_color = o->preserve_color;
729 n->reconstruct_threshold
731 n->reconstruct_bloom_vs_details =
d->reconstruct_bloom_vs_details;
732 n->reconstruct_grey_vs_color =
d->reconstruct_grey_vs_color;
733 n->reconstruct_structure_vs_texture =
d->reconstruct_structure_vs_texture;
734 n->reconstruct_feather = 3.0f;
736 n->auto_hardness =
TRUE;
737 n->custom_grey =
TRUE;
738 n->high_quality_reconstruction = 0;
739 n->noise_distribution =
d->noise_distribution;
740 n->noise_level = 0.f;
742 n->compensate_icc_black =
FALSE;
746 if(old_version == 2 && new_version == 5)
748 typedef struct dt_iop_filmicrgb_params_v2_t
750 float grey_point_source;
751 float black_point_source;
752 float white_point_source;
753 float reconstruct_threshold;
754 float reconstruct_feather;
755 float reconstruct_bloom_vs_details;
756 float reconstruct_grey_vs_color;
757 float reconstruct_structure_vs_texture;
758 float security_factor;
759 float grey_point_target;
760 float black_point_target;
761 float white_point_target;
771 int high_quality_reconstruction;
774 } dt_iop_filmicrgb_params_v2_t;
776 dt_iop_filmicrgb_params_v2_t *o = (dt_iop_filmicrgb_params_v2_t *)old_params;
782 n->grey_point_source = o->grey_point_source;
783 n->white_point_source = o->white_point_source;
784 n->black_point_source = o->black_point_source;
785 n->security_factor = o->security_factor;
786 n->grey_point_target = o->grey_point_target;
787 n->black_point_target = o->black_point_target;
788 n->white_point_target = o->white_point_target;
789 n->output_power = o->output_power;
790 n->latitude = o->latitude;
791 n->contrast = o->contrast;
792 n->saturation = o->saturation;
793 n->balance = o->balance;
794 n->preserve_color = o->preserve_color;
795 n->shadows = o->shadows;
796 n->highlights = o->highlights;
797 n->reconstruct_threshold = o->reconstruct_threshold;
798 n->reconstruct_bloom_vs_details = o->reconstruct_bloom_vs_details;
799 n->reconstruct_grey_vs_color = o->reconstruct_grey_vs_color;
800 n->reconstruct_structure_vs_texture = o->reconstruct_structure_vs_texture;
801 n->reconstruct_feather = o->reconstruct_feather;
802 n->version = o->version;
803 n->auto_hardness = o->auto_hardness;
804 n->custom_grey = o->custom_grey;
805 n->high_quality_reconstruction = o->high_quality_reconstruction;
806 n->noise_level =
d->noise_level;
807 n->noise_distribution =
d->noise_distribution;
808 n->noise_level = 0.f;
810 n->compensate_icc_black =
FALSE;
814 if(old_version == 3 && new_version == 5)
816 typedef struct dt_iop_filmicrgb_params_v3_t
818 float grey_point_source;
819 float black_point_source;
820 float white_point_source;
821 float reconstruct_threshold;
822 float reconstruct_feather;
823 float reconstruct_bloom_vs_details;
825 float reconstruct_grey_vs_color;
827 float reconstruct_structure_vs_texture;
829 float security_factor;
830 float grey_point_target;
831 float black_point_target;
832 float white_point_target;
843 gboolean auto_hardness;
844 gboolean custom_grey;
845 int high_quality_reconstruction;
847 int noise_distribution;
851 } dt_iop_filmicrgb_params_v3_t;
853 dt_iop_filmicrgb_params_v3_t *o = (dt_iop_filmicrgb_params_v3_t *)old_params;
859 n->grey_point_source = o->grey_point_source;
860 n->white_point_source = o->white_point_source;
861 n->black_point_source = o->black_point_source;
862 n->security_factor = o->security_factor;
863 n->grey_point_target = o->grey_point_target;
864 n->black_point_target = o->black_point_target;
865 n->white_point_target = o->white_point_target;
866 n->output_power = o->output_power;
867 n->latitude = o->latitude;
868 n->contrast = o->contrast;
869 n->saturation = o->saturation;
870 n->balance = o->balance;
871 n->preserve_color = o->preserve_color;
872 n->shadows = o->shadows;
873 n->highlights = o->highlights;
874 n->reconstruct_threshold = o->reconstruct_threshold;
875 n->reconstruct_bloom_vs_details = o->reconstruct_bloom_vs_details;
876 n->reconstruct_grey_vs_color = o->reconstruct_grey_vs_color;
877 n->reconstruct_structure_vs_texture = o->reconstruct_structure_vs_texture;
878 n->reconstruct_feather = o->reconstruct_feather;
879 n->version = o->version;
880 n->auto_hardness = o->auto_hardness;
881 n->custom_grey = o->custom_grey;
882 n->high_quality_reconstruction = o->high_quality_reconstruction;
883 n->noise_level =
d->noise_level;
884 n->noise_distribution =
d->noise_distribution;
885 n->noise_level =
d->noise_level;
887 n->compensate_icc_black =
FALSE;
891 if(old_version == 4 && new_version == 5)
893 typedef struct dt_iop_filmicrgb_params_v4_t
895 float grey_point_source;
896 float black_point_source;
897 float white_point_source;
898 float reconstruct_threshold;
899 float reconstruct_feather;
900 float reconstruct_bloom_vs_details;
901 float reconstruct_grey_vs_color;
902 float reconstruct_structure_vs_texture;
903 float security_factor;
904 float grey_point_target;
905 float black_point_target;
906 float white_point_target;
915 gboolean auto_hardness;
916 gboolean custom_grey;
917 int high_quality_reconstruction;
921 gboolean compensate_icc_black;
922 gint internal_version;
923 } dt_iop_filmicrgb_params_v4_t;
925 dt_iop_filmicrgb_params_v4_t *o = (dt_iop_filmicrgb_params_v4_t *)old_params;
929 switch(o->internal_version)
949static inline __attribute__((always_inline))
float pixel_rgb_norm_power_simd(
const dt_aligned_pixel_simd_t pixel)
954 float numerator = 0.0f;
955 float denominator = 0.0f;
957 for(
int c = 0; c < 3; c++)
959 const float value = fabsf(pixel[c]);
961 const float RGB_cubic = RGB_square *
value;
962 numerator += RGB_cubic;
963 denominator += RGB_square;
966 return numerator / fmaxf(denominator, 1e-12f);
972 return pixel_rgb_norm_power_simd(dt_load_simd_aligned(pixel));
989 return fmaxf(fmaxf(pixel[0], pixel[1]), pixel[2]);
998 return dt_ioppr_get_rgb_matrix_luminance(
rgb, work_profile->
matrix_in, work_profile->
lut_in,
999 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
1003 return work_profile->
matrix_in[1][0] * pixel[0] + work_profile->
matrix_in[1][1] * pixel[1]
1004 + work_profile->
matrix_in[1][2] * pixel[2];
1007 return pixel[0] * 0.2225045f + pixel[1] * 0.7168786f + pixel[2] * 0.0606169f;
1010 return pixel_rgb_norm_power_simd(pixel);
1013 return sqrtf(sqf(pixel[0]) + sqf(pixel[1]) + sqf(pixel[2]));
1016 return sqrtf(sqf(pixel[0]) + sqf(pixel[1]) + sqf(pixel[2])) *
INVERSE_SQRT_3;
1025 return dt_ioppr_get_rgb_matrix_luminance(
rgb, work_profile->
matrix_in, work_profile->
lut_in,
1026 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
1030 return work_profile->
matrix_in[1][0] * pixel[0] + work_profile->
matrix_in[1][1] * pixel[1]
1031 + work_profile->
matrix_in[1][2] * pixel[2];
1034 return pixel[0] * 0.2225045f + pixel[1] * 0.7168786f + pixel[2] * 0.0606169f;
1043 return get_pixel_norm_simd(dt_load_simd_aligned(pixel), variant, work_profile);
1048 const
float dynamic_range)
1050 return clamp_simd((log2f(
x / grey) - black) / dynamic_range);
1055 const
float dynamic_range)
1058 return grey * exp2f(dynamic_range *
x + black);
1077 if(
x < latitude_min)
1089 result = M3[2] + fmaxf(0.f, M3[0] * powf(fmaxf(
x, 0.f), M4[0]));
1094 const float ty = latitude_min * M2[2] + M1[2];
1095 const float u = M2[2] * (
x - latitude_min) / M1[0];
1096 result = M1[0] * (u / powf(1.f + powf(u, M2[0]), 1.f / M2[0])) + ty;
1102 result = M1[0] +
x * (M2[0] +
x * (M3[0] +
x * (M4[0] +
x * M5[0])));
1107 result = M1[0] +
x * (M2[0] +
x * (M3[0] +
x * M4[0]));
1112 const float xi = latitude_min -
x;
1113 const float rat = xi * (xi * M2[0] + 1.f);
1114 result = M4[0] - M1[0] * rat / (rat + M3[0]);
1117 else if(
x > latitude_max)
1125 result = M4[2] - fmaxf(0.f, M3[1] * powf(fmaxf(1.f -
x, 0.f), M4[1]));
1130 const float ty = latitude_max * M2[2] + M1[2];
1131 const float u = M2[2] * (
x - latitude_max) / M1[1];
1132 result = M1[1] * (u / powf(1.f + powf(u, M2[1]), 1.f / M2[1])) + ty;
1138 result = M1[1] +
x * (M2[1] +
x * (M3[1] +
x * (M4[1] +
x * M5[1])));
1143 result = M1[1] +
x * (M2[1] +
x * (M3[1] +
x * M4[1]));
1148 const float xi =
x - latitude_max;
1149 const float rat = xi * (xi * M2[1] + 1.f);
1150 result = M4[1] + M1[1] * rat / (rat + M3[1]);
1156 result = M1[2] +
x * M2[2];
1164filmic_desaturate_v1(
const float x,
const float sigma_toe,
const float sigma_shoulder,
1165 const float saturation)
1167 const float radius_toe =
x;
1168 const float radius_shoulder = 1.0f -
x;
1170 const float key_toe = expf(-0.5f * radius_toe * radius_toe / sigma_toe);
1171 const float key_shoulder = expf(-0.5f * radius_shoulder * radius_shoulder / sigma_shoulder);
1173 return 1.0f -
clamp_simd((key_toe + key_shoulder) / saturation);
1179filmic_desaturate_v2(
const float x,
const float sigma_toe,
const float sigma_shoulder,
1180 const float saturation)
1182 const float radius_toe =
x;
1183 const float radius_shoulder = 1.0f -
x;
1184 const float sat2 = 0.5f / sqrtf(saturation);
1185 const float key_toe = expf(-radius_toe * radius_toe / sigma_toe * sat2);
1186 const float key_shoulder = expf(-radius_shoulder * radius_shoulder / sigma_shoulder * sat2);
1188 return (saturation - (key_toe + key_shoulder) * (saturation));
1199#define MAX_NUM_SCALES 10
1202 const float normalize,
const float feathering,
const size_t width,
1203 const size_t height,
const size_t ch)
1215 const float pix_max = fmaxf(sqrtf(sqf(in[
k]) + sqf(in[
k + 1]) + sqf(in[
k + 2])), 0.f);
1216 const float argument = -pix_max *
normalize + feathering;
1224 clipped += (4.f > argument);
1228 return (clipped > 9);
1231 float *
const inpainted,
const float noise_level,
const float threshold,
1240 for(
size_t j = 0; j <
width; j++)
1250 const size_t idx =
i *
width + j;
1251 const size_t index = idx * 4;
1252 const float weight = mask[idx];
1253 const float *
const restrict pix_in = __builtin_assume_aligned(in + index, 16);
1265 float *
const restrict pix_out = __builtin_assume_aligned(inpainted + index, 16);
1273 const float *
const restrict texture,
const float *
const restrict mask,
1274 float *
const restrict reconstructed,
const size_t width,
1275 const size_t height,
const size_t ch,
const float gamma,
1276 const float gamma_comp,
const float beta,
const float beta_comp,
1277 const float delta,
const size_t s,
const size_t scales)
1282 const float alpha = mask[
k /
ch];
1285 const float *
const restrict HF_c = __builtin_assume_aligned(HF +
k, 16);
1286 const float *
const restrict LF_c = __builtin_assume_aligned(LF +
k, 16);
1287 const float *
const restrict TT_c = __builtin_assume_aligned(texture +
k, 16);
1296 const float grey_details = (HF_c[0] + HF_c[1] + HF_c[2]) / 3.f;
1301 const float grey_HF = beta_comp * (gamma_comp * grey_details + gamma * grey_texture);
1305 const float grey_residual = beta_comp * (LF_c[0] + LF_c[1] + LF_c[2]) / 3.f;
1306 __OMP_SIMD__(aligned(reconstructed:64) aligned(HF_c, LF_c, TT_c:16))
1307 for(
size_t c = 0; c < 4; c++)
1314 const float details = (gamma_comp * HF_c[c] + gamma * TT_c[c]) * beta + grey_HF;
1317 const float residual = (s == scales - 1) ? (grey_residual + LF_c[c] * beta) : 0.f;
1318 reconstructed[
k + c] += alpha * (
delta * details + residual);
1325 const float *
const restrict texture,
1326 const float *
const restrict mask,
1327 float *
const restrict reconstructed,
const size_t width,
1328 const size_t height,
const size_t ch,
const float gamma,
1329 const float gamma_comp,
const float beta,
const float beta_comp,
1330 const float delta,
const size_t s,
const size_t scales)
1348 const float alpha = mask[
k /
ch];
1351 const float *
const restrict HF_c = __builtin_assume_aligned(HF +
k, 16);
1352 const float *
const restrict LF_c = __builtin_assume_aligned(LF +
k, 16);
1353 const float *
const restrict TT_c = __builtin_assume_aligned(texture +
k, 16);
1362 const float grey_details = (HF_c[0] + HF_c[1] + HF_c[2]) / 3.f;
1367 const float grey_HF = (gamma_comp * grey_details + gamma * grey_texture);
1369 for(
size_t c = 0; c < 4; c++)
1373 const float details = 0.5f * ((gamma_comp * HF_c[c] + gamma * TT_c[c]) + grey_HF);
1376 const float residual = (s == scales - 1) ? LF_c[c] : 0.f;
1377 reconstructed[
k + c] += alpha * (
delta * details + residual);
1384static inline void init_reconstruct(
const float *
const restrict in,
const float *
const restrict mask,
1385 float *
const restrict reconstructed,
const size_t width,
1394 reconstructed[4*
k + c] = fmaxf(in[4*
k + c] * (1.f - mask[
k]), 0.f);
1401 float *
const restrict HF,
float *
const restrict texture,
1406 for(
size_t c = 0; c < 4; ++c) HF[4*
k + c] = texture[4*
k + c] = detail[4*
k + c] - LF[4*
k + c];
1431 const float *
const restrict in,
const float *
const restrict mask,
1432 float *
const restrict reconstructed,
1440 const int scales =
get_scales(pipe, roi_in, piece);
1476 for(
int s = 0; s < scales; ++s)
1478 const float *restrict detail;
1480 float *restrict HF_RGB_temp;
1487 HF_RGB_temp = LF_even;
1493 HF_RGB_temp = LF_odd;
1499 HF_RGB_temp = LF_even;
1502 const int mult = 1 << s;
1517 gamma, gamma_comp, beta, beta_comp,
delta, s, scales);
1520 gamma, gamma_comp, beta, beta_comp,
delta, s, scales);
1543 const float *
const restrict pix_in = in +
k;
1544 float *
const restrict pix_out =
out +
k;
1548 for(
int c = 0; c < 3; c++)
1553 const float lum = (work_profile)
1554 ? dt_ioppr_get_rgb_matrix_luminance(temp, work_profile->
matrix_in, work_profile->
lut_in,
1555 work_profile->unbounded_coeffs_in,
1563 for(
int c = 0; c < 3; c++)
1566 spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1568 spline.
y[0], spline.
y[4]),
1584 const float *
const restrict pix_in = in +
k;
1585 float *
const restrict pix_out =
out +
k;
1589 for(
int c = 0; c < 3; c++)
1594 const float lum = (work_profile)
1595 ? dt_ioppr_get_rgb_matrix_luminance(temp, work_profile->
matrix_in, work_profile->
lut_in,
1596 work_profile->unbounded_coeffs_in,
1604 for(
int c = 0; c < 3; c++)
1607 spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1609 spline.
y[0], spline.
y[4]),
1625 const float *
const restrict pix_in = in +
k;
1626 float *
const restrict pix_out =
out +
k;
1629 float norm = fmaxf(get_pixel_norm(pix_in, variant, work_profile),
NORM_MIN);
1633 ratios[c] = pix_in[c] / norm;
1636 const float min_ratios = fminf(fminf(ratios[0], ratios[1]), ratios[2]);
1637 if(min_ratios < 0.0f)
1648 const float lum = (work_profile) ? dt_ioppr_get_rgb_matrix_luminance(
1649 ratios, work_profile->
matrix_in, work_profile->
lut_in, work_profile->unbounded_coeffs_in,
1654 for(
int c = 0; c < 3; c++) ratios[c] =
linear_saturation(ratios[c], lum, desaturation) / norm;
1658 norm = powf(
CLAMPF(filmic_spline(norm, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1660 spline.
y[0], spline.
y[4]),
1680 const float *
const restrict pix_in = in +
k;
1681 float *
const restrict pix_out =
out +
k;
1683 float norm = fmaxf(get_pixel_norm(pix_in, variant, work_profile),
NORM_MIN);
1689 ratios[c] = pix_in[c] / norm;
1692 const float min_ratios = fminf(fminf(ratios[0], ratios[1]), ratios[2]);
1693 const int sanitize = (min_ratios < 0.0f);
1697 ratios[c] -= min_ratios;
1707 norm = powf(
CLAMPF(filmic_spline(norm, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1709 spline.
y[0], spline.
y[4]),
1713 for(
int c = 0; c < 3; c++) ratios[c] = fmaxf(ratios[c] + (1.0f - ratios[c]) * (1.0f - desaturation), 0.0f);
1718 norm /= fmaxf(get_pixel_norm(ratios, variant, work_profile),
NORM_MIN);
1721 pix_out[c] = ratios[c] * norm;
1724 const float max_pix = fmaxf(fmaxf(pix_out[0], pix_out[1]), pix_out[2]);
1725 const int penalize = (max_pix > 1.0f);
1732 ratios[c] = fmaxf(ratios[c] + (1.0f - max_pix), 0.0f);
1733 pix_out[c] = ratios[c] * norm;
1740static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1741pipe_RGB_to_Ych_simd(
const dt_aligned_pixel_simd_t in,
const dt_aligned_pixel_simd_t matrix0,
1742 const dt_aligned_pixel_simd_t matrix1,
const dt_aligned_pixel_simd_t matrix2)
1753 const dt_aligned_pixel_simd_t
Yrg = LMS_to_Yrg_simd(dt_mat3x4_mul_vec4(in, matrix0, matrix1, matrix2));
1754 const float r =
Yrg[1] - 0.21902143f;
1755 const float g =
Yrg[2] - 0.54371398f;
1756 const float c = dt_fast_hypotf(
g,
r);
1757 const float cos_h =
c != 0.f ?
r /
c : 1.f;
1758 const float sin_h =
c != 0.f ?
g /
c : 0.f;
1759 return (dt_aligned_pixel_simd_t){
Yrg[0],
c, cos_h, sin_h };
1763static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1764Ych_to_pipe_RGB_simd(
const dt_aligned_pixel_simd_t in,
const dt_aligned_pixel_simd_t matrix0,
1765 const dt_aligned_pixel_simd_t matrix1,
const dt_aligned_pixel_simd_t matrix2)
1770 const dt_aligned_pixel_simd_t
Yrg = {
1772 in[1] * in[2] + 0.21902143f,
1773 in[1] * in[3] + 0.54371398f,
1776 return dt_mat3x4_mul_vec4(Yrg_to_LMS_simd(Yrg), matrix0, matrix1, matrix2);
1779static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1780filmic_desaturate_v4(
const dt_aligned_pixel_simd_t Ych_original, dt_aligned_pixel_simd_t Ych_final,
1781 const float saturation)
1789 const float chroma_original = Ych_original[1] * Ych_original[0];
1790 float chroma_final = Ych_final[1] * Ych_final[0];
1799 const float delta_chroma = saturation * (chroma_original - chroma_final);
1801 const int filmic_brightens = (Ych_final[0] > Ych_original[0]);
1802 const int filmic_resat = (chroma_original < chroma_final);
1803 const int filmic_desat = (chroma_original > chroma_final);
1804 const int user_resat = (saturation > 0.f);
1805 const int user_desat = (saturation < 0.f);
1807 chroma_final = (filmic_brightens && filmic_resat)
1808 ? (chroma_original + chroma_final) / 2.f
1809 : ((user_resat && filmic_desat) || user_desat)
1810 ? chroma_final + delta_chroma
1813 Ych_final[1] = fmaxf(chroma_final / Ych_final[0], 0.f);
1823#define CIE_Y_1931_to_CIE_Y_2006(x) (1.05785528f * (x))
1827clip_chroma_white_raw(
const float coeffs[3],
const float target_white,
const float Y,
1828 const float cos_h,
const float sin_h)
1830 const float denominator_Y_coeff = coeffs[0] * (0.979381443298969f * cos_h + 0.391752577319588f * sin_h)
1831 + coeffs[1] * (0.0206185567010309f * cos_h + 0.608247422680412f * sin_h)
1832 - coeffs[2] * (cos_h + sin_h);
1833 const float denominator_target_term = target_white * (0.68285981628866f * cos_h + 0.482137060515464f * sin_h);
1836 if(denominator_Y_coeff == 0.f)
return FLT_MAX;
1841 const float Y_asymptote = denominator_target_term / denominator_Y_coeff;
1842 if(Y <= Y_asymptote)
return FLT_MAX;
1848 const float denominator = Y * denominator_Y_coeff - denominator_target_term;
1849 const float numerator = -0.427506877216495f
1850 * (Y * (coeffs[0] + 0.856492345150334f * coeffs[1] + 0.554995960637719f * coeffs[2])
1851 - 0.988237752433297f * target_white);
1853 return numerator / denominator;
1858clip_chroma_white(
const float coeffs[3],
const float target_white,
const float Y,
1859 const float cos_h,
const float sin_h)
1865 const float eps = 1e-3f;
1867 const float delta_Y =
MAX(max_Y - Y, 0.f);
1871 max_chroma = delta_Y / (
eps * max_Y) * clip_chroma_white_raw(coeffs, target_white, (1.f -
eps) * max_Y, cos_h, sin_h);
1875 max_chroma = clip_chroma_white_raw(coeffs, target_white, Y, cos_h, sin_h);
1877 return max_chroma >= 0.f ? max_chroma : FLT_MAX;
1882clip_chroma_black(
const float coeffs[3],
const float cos_h,
const float sin_h)
1891 const float denominator = coeffs[0] * (0.979381443298969f * cos_h + 0.391752577319588f * sin_h)
1892 + coeffs[1] * (0.0206185567010309f * cos_h + 0.608247422680412f * sin_h)
1893 - coeffs[2] * (cos_h + sin_h);
1896 if(denominator == 0.f)
return FLT_MAX;
1898 const float numerator = -0.427506877216495f * (coeffs[0] + 0.856492345150334f * coeffs[1] + 0.554995960637719f * coeffs[2]);
1899 const float max_chroma = numerator / denominator;
1900 return max_chroma >= 0.f ? max_chroma : FLT_MAX;
1905clip_chroma(
const dt_colormatrix_t matrix_out,
const float target_white,
const float Y,
1906 const float cos_h,
const float sin_h,
const float chroma)
1914 const float chroma_R_white = clip_chroma_white(matrix_out[0], target_white, Y, cos_h, sin_h);
1915 const float chroma_G_white = clip_chroma_white(matrix_out[1], target_white, Y, cos_h, sin_h);
1916 const float chroma_B_white = clip_chroma_white(matrix_out[2], target_white, Y, cos_h, sin_h);
1917 const float max_chroma_white =
MIN(
MIN(chroma_R_white, chroma_G_white), chroma_B_white);
1919 const float chroma_R_black = clip_chroma_black(matrix_out[0], cos_h, sin_h);
1920 const float chroma_G_black = clip_chroma_black(matrix_out[1], cos_h, sin_h);
1921 const float chroma_B_black = clip_chroma_black(matrix_out[2], cos_h, sin_h);
1922 const float max_chroma_black =
MIN(
MIN(chroma_R_black, chroma_G_black), chroma_B_black);
1924 return MIN(
MIN(chroma, max_chroma_black), max_chroma_white);
1928static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1929gamut_check_Yrg_filmic_simd(
const dt_aligned_pixel_simd_t Ych)
1933 const dt_aligned_pixel_simd_t
Yrg = {
1935 Ych[1] * Ych[2] + 0.21902143f,
1936 Ych[1] * Ych[3] + 0.54371398f,
1939 float max_c = Ych[1];
1941 if(Yrg[1] < 0.f) max_c = fminf(-0.21902143f / Ych[2], max_c);
1942 if(Yrg[2] < 0.f) max_c = fminf(-0.54371398f / Ych[3], max_c);
1943 if(Yrg[1] + Yrg[2] > 1.f) max_c = fminf((1.f - 0.21902143f - 0.54371398f) / (Ych[2] + Ych[3]), max_c);
1945 return (dt_aligned_pixel_simd_t){ Ych[0], max_c, Ych[2], Ych[3] };
1949static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1950gamut_check_RGB_simd(
const dt_colormatrix_t matrix_out,
const dt_aligned_pixel_simd_t matrix_in0,
1951 const dt_aligned_pixel_simd_t matrix_in1,
const dt_aligned_pixel_simd_t matrix_in2,
1952 const dt_aligned_pixel_simd_t matrix_out0,
const dt_aligned_pixel_simd_t matrix_out1,
1953 const dt_aligned_pixel_simd_t matrix_out2,
const float display_black,
1954 const float display_white,
const dt_aligned_pixel_simd_t Ych_in)
1958 dt_aligned_pixel_simd_t RGB_brightened = Ych_to_pipe_RGB_simd(Ych_in, matrix_out0, matrix_out1, matrix_out2);
1959 const float min_pix =
MIN(
MIN(RGB_brightened[0], RGB_brightened[1]), RGB_brightened[2]);
1960 const float black_offset =
MAX(-min_pix, 0.f);
1963 const dt_aligned_pixel_simd_t Ych_brightened
1964 = pipe_RGB_to_Ych_simd(RGB_brightened, matrix_in0, matrix_in1, matrix_in2);
1970 const float Y = CLAMP((Ych_in[0] + Ych_brightened[0]) / 2.f,
1973 const float new_chroma = clip_chroma(matrix_out, display_white, Y, Ych_in[2], Ych_in[3], Ych_in[1]);
1976 dt_aligned_pixel_simd_t RGB_out
1977 = Ych_to_pipe_RGB_simd((dt_aligned_pixel_simd_t){
Y, new_chroma, Ych_in[2], Ych_in[3] },
1978 matrix_out0, matrix_out1, matrix_out2);
1986static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1987gamut_mapping_simd(dt_aligned_pixel_simd_t Ych_final,
const dt_aligned_pixel_simd_t Ych_original,
1988 const dt_colormatrix_t output_matrix,
const dt_aligned_pixel_simd_t input_matrix0,
1989 const dt_aligned_pixel_simd_t input_matrix1,
const dt_aligned_pixel_simd_t input_matrix2,
1990 const dt_aligned_pixel_simd_t output_matrix0,
const dt_aligned_pixel_simd_t output_matrix1,
1991 const dt_aligned_pixel_simd_t output_matrix2,
1992 const dt_colormatrix_t export_output_matrix,
const dt_aligned_pixel_simd_t export_input_matrix0,
1993 const dt_aligned_pixel_simd_t export_input_matrix1,
const dt_aligned_pixel_simd_t export_input_matrix2,
1994 const dt_aligned_pixel_simd_t export_output_matrix0,
const dt_aligned_pixel_simd_t export_output_matrix1,
1995 const dt_aligned_pixel_simd_t export_output_matrix2,
const float display_black,
1996 const float display_white,
const float saturation,
const int use_output_profile)
1999 Ych_final[2] = Ych_original[2];
2000 Ych_final[3] = Ych_original[3];
2006 Ych_final = filmic_desaturate_v4(Ych_original, Ych_final, saturation);
2007 Ych_final = gamut_check_Yrg_filmic_simd(Ych_final);
2009 if(!use_output_profile)
2013 return gamut_check_RGB_simd(output_matrix, input_matrix0, input_matrix1, input_matrix2,
2014 output_matrix0, output_matrix1, output_matrix2,
2015 display_black, display_white, Ych_final);
2020 dt_aligned_pixel_simd_t pix_out
2021 = gamut_check_RGB_simd(export_output_matrix, export_input_matrix0, export_input_matrix1, export_input_matrix2,
2022 export_output_matrix0, export_output_matrix1, export_output_matrix2,
2023 display_black, display_white, Ych_final);
2026 const dt_aligned_pixel_simd_t
LMS
2027 = dt_mat3x4_mul_vec4(pix_out, export_input_matrix0, export_input_matrix1, export_input_matrix2);
2029 return dt_mat3x4_mul_vec4(
LMS, output_matrix0, output_matrix1, output_matrix2);
2050 const int use_output_profile = (!
IS_NULL_PTR(export_profile));
2051 if(use_output_profile)
2062 return use_output_profile;
2099 simd_matrices->
input[
row] = dt_colormatrix_row_to_simd(input_matrix_t,
row);
2100 simd_matrices->
output[
row] = dt_colormatrix_row_to_simd(output_matrix_t,
row);
2101 simd_matrices->
export_input[
row] = dt_colormatrix_row_to_simd(export_input_matrix_t,
row);
2102 simd_matrices->
export_output[
row] = dt_colormatrix_row_to_simd(export_output_matrix_t,
row);
2106static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2107norm_tone_mapping_v4_simd(
const dt_aligned_pixel_simd_t pix_in,
2112 const float norm_min,
const float norm_max)
2116 float norm =
CLAMPF(get_pixel_norm_simd(pix_in,
type, work_profile), norm_min, norm_max);
2118 const dt_aligned_pixel_simd_t ratios = pix_in /
dt_simd_set1(norm);
2126 spline.
y[0], spline.
y[4]),
2133static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2139 dt_aligned_pixel_simd_t pix_out = pix_in;
2140 for(
size_t c = 0;
c < 3;
c++)
2143 pix_out[
c] = powf(
CLAMPF(filmic_spline(mapped, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
2160 const float display_black,
const float display_white)
2168 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2169 export_output_matrix, work_profile, export_profile);
2178 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2179 const dt_aligned_pixel_simd_t pix_out
2180 = norm_tone_mapping_v4_simd(pix_in, variant, work_profile, data, spline, norm_min, norm_max);
2183 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2184 simd_matrices.
input[1], simd_matrices.
input[2]);
2185 const dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2186 simd_matrices.
input[1], simd_matrices.
input[2]);
2188 dt_store_simd_nontemporal(
out +
k,
2189 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2190 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2192 export_output_matrix,
2195 display_black, display_white, data->
saturation, use_output_profile));
2208 const float display_black,
const float display_white)
2217 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2218 export_output_matrix, work_profile, export_profile);
2224 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2225 const dt_aligned_pixel_simd_t pix_out = RGB_tone_mapping_v4_simd(pix_in, data, spline);
2226 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2227 simd_matrices.
input[1], simd_matrices.
input[2]);
2228 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2229 simd_matrices.
input[1], simd_matrices.
input[2]);
2231 Ych_final[1] = fminf(Ych_original[1], Ych_final[1]);
2233 dt_store_simd_nontemporal(
out +
k,
2234 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2235 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2237 export_output_matrix,
2240 display_black, display_white, data->
saturation, use_output_profile));
2247static inline void filmic_v5(
const float *
const restrict in,
float *
const restrict
out,
2252 const size_t height,
const size_t ch,
const float display_black,
2253 const float display_white)
2262 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2263 export_output_matrix, work_profile, export_profile);
2272 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2273 const dt_aligned_pixel_simd_t naive_rgb = RGB_tone_mapping_v4_simd(pix_in, data, spline);
2274 const dt_aligned_pixel_simd_t max_rgb
2281 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2282 simd_matrices.
input[1], simd_matrices.
input[2]);
2284 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2285 simd_matrices.
input[1], simd_matrices.
input[2]);
2287 Ych_final[1] = fminf(Ych_original[1], Ych_final[1]);
2289 dt_store_simd_nontemporal(
out +
k,
2290 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2291 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2293 export_output_matrix,
2296 display_black, display_white, 0.f, use_output_profile));
2318 dot_product(xyz_D50, XYZ_D50_to_D65_CAT16, xyz_D65);
2334 for(
size_t r = 0;
r < 4;
r++)
2335 for(
size_t c = 0; c < 4; c++)
M[
r][c] = (
r == c &&
r < 3) ? 1.f : 0.f;
2345 const float inset[3],
const float rotation[3],
2351 for(
size_t r = 0;
r < 3;
r++)
2352 for(
size_t c = 0; c < 3; c++) white_xyz[
r] += work_profile->
matrix_in[
r][c];
2356 for(
size_t i = 0;
i < 3;
i++)
2364 const float dr = primary_Yrg[1] - white_Yrg[1];
2365 const float dg = primary_Yrg[2] - white_Yrg[2];
2366 const float scale = 1.f -
CLAMPF(inset[
i], 0.f, 0.9f);
2367 const float cos_a = cosf(rotation[
i]);
2368 const float sin_a = sinf(rotation[
i]);
2370 white_Yrg[1] + scale * (cos_a * dr - sin_a * dg),
2371 white_Yrg[2] + scale * (sin_a * dr + cos_a * dg), 0.f };
2374 for(
size_t r = 0;
r < 3;
r++) P_prime[
r][
i] = displaced_xyz[
r];
2382 dot_product(white_xyz, P_prime_inv, s);
2383 for(
size_t r = 0;
r < 3;
r++)
2384 for(
size_t c = 0; c < 3; c++) P_prime[
r][c] *= s[c];
2409 float inset_anchor[3], rotation_anchor[3], outset_anchor[3], outset_rotation[3];
2414 inset_anchor[0] = +0.6410825f; inset_anchor[1] = +0.6898110f; inset_anchor[2] = +0.3194529f;
2415 rotation_anchor[0] = +0.0405734f; rotation_anchor[1] = +0.1631286f; rotation_anchor[2] = +0.0350584f;
2416 outset_anchor[0] = 0.784757f; outset_anchor[1] = 0.789387f; outset_anchor[2] = 0.445403f;
2417 outset_rotation[0] = -0.0057845f; outset_rotation[1] = +0.1593207f; outset_rotation[2] = -0.0592955f;
2421 inset_anchor[0] = +0.6509540f; inset_anchor[1] = +0.7488775f; inset_anchor[2] = +0.3517703f;
2422 rotation_anchor[0] = +0.0278602f; rotation_anchor[1] = +0.1214671f; rotation_anchor[2] = -0.0228829f;
2423 outset_anchor[0] = 0.793082f; outset_anchor[1] = 0.815169f; outset_anchor[2] = 0.460318f;
2424 outset_rotation[0] = -0.0053781f; outset_rotation[1] = +0.1187604f; outset_rotation[2] = -0.0794801f;
2428 inset_anchor[0] = +0.6379749f; inset_anchor[1] = +0.7878689f; inset_anchor[2] = +0.3753822f;
2429 rotation_anchor[0] = +0.0106096f; rotation_anchor[1] = +0.0582598f; rotation_anchor[2] = -0.0696729f;
2430 outset_anchor[0] = 0.790237f; outset_anchor[1] = 0.831376f; outset_anchor[2] = 0.465406f;
2431 outset_rotation[0] = -0.0080070f; outset_rotation[1] = +0.0571100f; outset_rotation[2] = -0.0912220f;
2435 inset_anchor[0] = +0.5770235f; inset_anchor[1] = +0.8102094f; inset_anchor[2] = +0.4000390f;
2436 rotation_anchor[0] = -0.0081060f; rotation_anchor[1] = -0.0034008f; rotation_anchor[2] = -0.1035236f;
2437 outset_anchor[0] = 0.766420f; outset_anchor[1] = 0.838020f; outset_anchor[2] = 0.465130f;
2438 outset_rotation[0] = -0.0122011f; outset_rotation[1] = -0.0021732f; outset_rotation[2] = -0.0971215f;
2443 inset_anchor[0] = +0.5991055f; inset_anchor[1] = +0.6000000f; inset_anchor[2] = +0.3300009f;
2444 rotation_anchor[0] = +0.0571015f; rotation_anchor[1] = +0.1999891f; rotation_anchor[2] = +0.0886110f;
2445 outset_anchor[0] = 0.761433f; outset_anchor[1] = 0.752267f; outset_anchor[2] = 0.465293f;
2446 outset_rotation[0] = -0.0034297f; outset_rotation[1] = +0.1952448f; outset_rotation[2] = -0.0480109f;
2461static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2462filmic_agx_compress_negatives(
const dt_aligned_pixel_simd_t pix,
const dt_aligned_pixel_simd_t luma_coeffs)
2469 const float input_y = pix[0] * luma_coeffs[0] + pix[1] * luma_coeffs[1] + pix[2] * luma_coeffs[2];
2470 const float max_rgb = fmaxf(fmaxf(pix[0], pix[1]), pix[2]);
2471 const float min_rgb = fminf(fminf(pix[0], pix[1]), pix[2]);
2473 const dt_aligned_pixel_simd_t opponent =
dt_simd_set1(max_rgb) - pix;
2474 const float opponent_y = opponent[0] * luma_coeffs[0] + opponent[1] * luma_coeffs[1] + opponent[2] * luma_coeffs[2];
2475 const float max_opponent = fmaxf(fmaxf(opponent[0], opponent[1]), opponent[2]);
2476 const float y_compensated = max_opponent - opponent_y + input_y;
2478 const float offset = fmaxf(-min_rgb, 0.f);
2479 const dt_aligned_pixel_simd_t shifted = pix +
dt_simd_set1(offset);
2480 const float max_shifted = fmaxf(fmaxf(shifted[0], shifted[1]), shifted[2]);
2481 const dt_aligned_pixel_simd_t opponent_shifted =
dt_simd_set1(max_shifted) - shifted;
2482 const float max_opponent_shifted
2483 = fmaxf(fmaxf(opponent_shifted[0], opponent_shifted[1]), opponent_shifted[2]);
2484 const float y_opponent_shifted = opponent_shifted[0] * luma_coeffs[0] + opponent_shifted[1] * luma_coeffs[1]
2485 + opponent_shifted[2] * luma_coeffs[2];
2487 = shifted[0] * luma_coeffs[0] + shifted[1] * luma_coeffs[1] + shifted[2] * luma_coeffs[2];
2488 y_new += max_opponent_shifted - y_opponent_shifted;
2490 const float ratio = (y_new > y_compensated && y_new > 1e-6f) ? y_compensated / y_new : 1.f;
2495static inline void filmic_agx(
const float *
const restrict in,
float *
const restrict
out,
2500 const size_t height,
const size_t ch,
const float display_black,
2501 const float display_white)
2509 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2510 export_output_matrix, work_profile, export_profile);
2521 const dt_aligned_pixel_simd_t inset0 = dt_colormatrix_row_to_simd(inset_t, 0);
2522 const dt_aligned_pixel_simd_t inset1 = dt_colormatrix_row_to_simd(inset_t, 1);
2523 const dt_aligned_pixel_simd_t inset2 = dt_colormatrix_row_to_simd(inset_t, 2);
2524 const dt_aligned_pixel_simd_t outset0 = dt_colormatrix_row_to_simd(outset_t, 0);
2525 const dt_aligned_pixel_simd_t outset1 = dt_colormatrix_row_to_simd(outset_t, 1);
2526 const dt_aligned_pixel_simd_t outset2 = dt_colormatrix_row_to_simd(outset_t, 2);
2528 const dt_aligned_pixel_simd_t luma_coeffs = { work_profile->
matrix_in[1][0], work_profile->
matrix_in[1][1],
2535 dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2536 for(
size_t c = 0; c < 3; c++) pix_in[c] = isnan(pix_in[c]) ? 0.f :
CLAMPF(pix_in[c], -1e6f, 1e6f);
2537 const dt_aligned_pixel_simd_t compressed = filmic_agx_compress_negatives(pix_in, luma_coeffs);
2541 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(compressed, simd_matrices.
input[0],
2542 simd_matrices.
input[1], simd_matrices.
input[2]);
2544 dt_aligned_pixel_simd_t rendering = dt_mat3x4_mul_vec4(compressed, inset0, inset1, inset2);
2545 rendering = RGB_tone_mapping_v4_simd(rendering, data, spline);
2546 const dt_aligned_pixel_simd_t pix_out = dt_mat3x4_mul_vec4(rendering, outset0, outset1, outset2);
2548 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2549 simd_matrices.
input[1], simd_matrices.
input[2]);
2551 const float chroma_final = fminf(Ych_original[1], Ych_final[1]);
2567 const float r_mix = beta_hue * Ych_original[1] * Ych_original[2]
2568 + (1.f - beta_hue) * chroma_final * Ych_final[2];
2569 const float g_mix = beta_hue * Ych_original[1] * Ych_original[3]
2570 + (1.f - beta_hue) * chroma_final * Ych_final[3];
2571 const float norm_mix = dt_fast_hypotf(g_mix, r_mix);
2572 dt_aligned_pixel_simd_t Ych_reference = Ych_original;
2573 Ych_reference[2] = (norm_mix > 1e-9f) ? r_mix / norm_mix : Ych_original[2];
2574 Ych_reference[3] = (norm_mix > 1e-9f) ? g_mix / norm_mix : Ych_original[3];
2575 Ych_final[1] = chroma_final;
2577 dt_store_simd_nontemporal(
out +
k,
2578 gamut_mapping_simd(Ych_final, Ych_reference, output_matrix,
2579 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2581 export_output_matrix,
2584 display_black, display_white, 0.f, use_output_profile));
2591static inline void display_mask(
const float *
const restrict mask,
float *
const restrict
out,
2604static inline void compute_ratios(
const float *
const restrict in,
float *
const restrict norms,
2605 float *
const restrict ratios,
2607 const int variant,
const size_t width,
const size_t height)
2612 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2613 const float norm = fmaxf(get_pixel_norm_simd(pix_in, variant, work_profile),
NORM_MIN);
2614 norms[
k / 4] = norm;
2615 dt_store_simd_nontemporal(ratios +
k, pix_in /
dt_simd_set1(norm));
2622static inline void restore_ratios(
float *
const restrict ratios,
const float *
const restrict norms,
2628 dt_aligned_pixel_simd_t ratio = dt_load_simd_aligned(ratios + 4 *
k);
2629 const float norm = norms[
k];
2634 dt_store_simd_nontemporal(ratios + 4 *
k, ratio);
2662 && !isnan(softproof_profile->
matrix_out[0][0]))
2663 return softproof_profile;
2674 tiling->maxbuf_cl = 1.0f;
2691 tiling->factor_cl = 2.0f;
2696 const int scales =
get_scales(pipe, roi_in, piece);
2697 const int max_filter_radius = (1 << scales);
2701 tiling->factor_cl = 9.0f;
2702 tiling->overlap = max_filter_radius;
2708 const void *
const restrict ivoid,
2709 void *
const restrict
ovoid)
2717 const size_t ch = 4;
2728 float *restrict in = (
float *)ivoid;
2729 float *
const restrict
out = (
float *)
ovoid;
2735 float *
const restrict mask
2736 = hl_deprecated ? NULL
2744 const int recover_highlights
2745 = hl_deprecated ?
FALSE
2763 float *
const restrict reconstructed
2764 = recover_highlights
2767 if(recover_highlights &&
IS_NULL_PTR(reconstructed))
2822 data, piece, roi_in, roi_out))
2847 const float white_display = powf(data->spline.y[4], data->
output_power);
2848 const float black_display = powf(data->spline.y[0], data->
output_power);
2854 filmic_agx(in,
out, work_profile, export_profile, data, data->spline, roi_out->
width,
2855 roi_out->
height,
ch, black_display, white_display);
2859 filmic_v5(in,
out, work_profile, export_profile, data, data->spline, roi_out->
width,
2860 roi_out->
height,
ch, black_display, white_display);
2904 const int devid = pipe->
devid;
2910 const int scales =
get_scales(pipe, roi_in, piece);
2923 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
2934 if(err != CL_SUCCESS)
goto error;
2952 for(
int s = 0; s < scales; ++s)
2974 const int mult = 1 << s;
2977 const int clamp_lf = 1;
2980 .yoffset = 0, .yfactor = 1,
2981 .cellsize = 4 *
sizeof(float), .overhead = 0,
2982 .sizex = 1 << 16, .sizey = 1 };
2984 hblocksize = hlocopt.
sizex;
2991 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
2999 (hblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
3001 horizontal_sizes, horizontal_local);
3013 if(err != CL_SUCCESS)
goto error;
3017 .yoffset = 2 * mult, .yfactor = 1,
3018 .cellsize = 4 *
sizeof(float), .overhead = 0,
3019 .sizex = 1, .sizey = 1 << 16 };
3021 vblocksize = vlocopt.
sizey;
3028 const size_t vertical_local[3] = { 1, vblocksize, 1 };
3036 (vblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
3038 vertical_sizes, vertical_local);
3050 if(err != CL_SUCCESS)
goto error;
3060 if(err != CL_SUCCESS)
goto error;
3063 size_t origin[] = { 0, 0, 0 };
3065 if(err != CL_SUCCESS)
goto error;
3068 const int blur_size = 1;
3069 const int clamp_hf = 0;
3077 if(err != CL_SUCCESS)
goto error;
3086 if(err != CL_SUCCESS)
goto error;
3106 if(err != CL_SUCCESS)
goto error;
3127 const int devid = pipe->
devid;
3134 cl_mem inpainted = NULL;
3135 cl_mem reconstructed = NULL;
3137 cl_mem ratios = NULL;
3138 cl_mem norms = NULL;
3143 const int use_work_profile = (
IS_NULL_PTR(work_profile)) ? 0 : 1;
3151 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
3152 export_output_matrix, work_profile, export_profile);
3157 float input_matrix_3x4[12];
3158 float output_matrix_3x4[12];
3164 cl_mem export_input_matrix_cl = NULL;
3165 cl_mem export_output_matrix_cl = NULL;
3168 cl_mem inset_matrix_cl = NULL;
3169 cl_mem outset_matrix_cl = NULL;
3170 float luma_coeffs[4] = { work_profile->
matrix_in[1][0], work_profile->
matrix_in[1][1],
3177 float inset_3x4[12];
3178 float outset_3x4[12];
3185 cl_mem dev_profile_info = NULL;
3186 cl_mem dev_profile_lut = NULL;
3188 cl_float *profile_lut_cl = NULL;
3190 cl_mem clipped = NULL;
3193 &dev_profile_info, &dev_profile_lut);
3194 if(err != CL_SUCCESS)
goto error;
3196 if(use_output_profile)
3198 float export_input_matrix_3x4[12];
3199 float export_output_matrix_3x4[12];
3211 const gboolean hl_deprecated =
d->hl_deprecated;
3213 uint32_t is_clipped = 0;
3218 if(err != CL_SUCCESS)
goto error;
3230 if(err != CL_SUCCESS)
goto error;
3234 if(err != CL_SUCCESS)
goto error;
3266 const float noise_level =
d->noise_level / scale;
3277 if(err != CL_SUCCESS)
goto error;
3282 if(err != CL_SUCCESS)
goto error;
3286 if(
d->high_quality_reconstruction > 0)
3293 for(
int i = 0;
i <
d->high_quality_reconstruction;
i++)
3303 if(err != CL_SUCCESS)
goto error;
3307 if(err != CL_SUCCESS)
goto error;
3316 if(err != CL_SUCCESS)
goto error;
3334 const float white_display = powf(spline.
y[4],
d->output_power);
3335 const float black_display = powf(spline.
y[0],
d->output_power);
3375 if(err != CL_SUCCESS)
goto error;
3421 if(err != CL_SUCCESS)
goto error;
3461 const float grey = get_pixel_norm(self->
picked_color,
p->preserve_color, work_profile) / 2.0f;
3463 const float prev_grey =
p->grey_point_source;
3464 p->grey_point_source = CLAMP(100.f * grey, 0.001f, 100.0f);
3465 const float grey_var = log2f(prev_grey /
p->grey_point_source);
3466 p->black_point_source =
p->black_point_source - grey_var;
3467 p->white_point_source =
p->white_point_source + grey_var;
3468 p->output_power = logf(
p->grey_point_target / 100.0f)
3469 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3478 gtk_widget_queue_draw(self->
gui->
widget);
3492 float EVmin = CLAMP(log2f(black / (
p->grey_point_source / 100.0f)), -16.0f, -1.0f);
3493 EVmin *= (1.0f +
p->security_factor / 100.0f);
3495 p->black_point_source = fmaxf(EVmin, -16.0f);
3496 p->output_power = logf(
p->grey_point_target / 100.0f)
3497 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3504 gtk_widget_queue_draw(self->
gui->
widget);
3519 float EVmax = CLAMP(log2f(white / (
p->grey_point_source / 100.0f)), 1.0f, 16.0f);
3520 EVmax *= (1.0f +
p->security_factor / 100.0f);
3522 p->white_point_source = EVmax;
3523 p->output_power = logf(
p->grey_point_target / 100.0f)
3524 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3531 gtk_widget_queue_draw(self->
gui->
widget);
3544 const float grey = get_pixel_norm(self->
picked_color,
p->preserve_color, work_profile) / 2.0f;
3545 p->grey_point_source = CLAMP(100.f * grey, 0.001f, 100.0f);
3550 float EVmax = CLAMP(log2f(white / (
p->grey_point_source / 100.0f)), 1.0f, 16.0f);
3551 EVmax *= (1.0f +
p->security_factor / 100.0f);
3555 float EVmin = CLAMP(log2f(black / (
p->grey_point_source / 100.0f)), -16.0f, -1.0f);
3556 EVmin *= (1.0f +
p->security_factor / 100.0f);
3558 p->black_point_source = fmaxf(EVmin, -16.0f);
3559 p->white_point_source = EVmax;
3560 p->output_power = logf(
p->grey_point_target / 100.0f)
3561 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3570 gtk_widget_queue_draw(self->
gui->
widget);
3584 const float *
const restrict in = (
const float *)
i;
3586 float min_Y = INFINITY;
3587 float max_RGB = 0.0f;
3590 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
3594 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
3597 if(isfinite(
XYZ[1]))
3598 min_Y = fminf(min_Y,
XYZ[1]);
3600 const float pixel_max = fmaxf(in[
k], fmaxf(in[
k + 1], in[
k + 2]));
3601 if(isfinite(pixel_max))
3602 max_RGB = fmaxf(max_RGB, pixel_max);
3605 if(!isfinite(min_Y) || !isfinite(max_RGB))
return;
3607 const float grey =
p->grey_point_source / 100.0f;
3608 const float white = fmaxf(max_RGB,
NORM_MIN);
3609 const float black = fmaxf(min_Y,
NORM_MIN);
3611 float EVmax = CLAMP(log2f(white / grey), 1.0f, 16.0f);
3612 EVmax *= (1.0f +
p->security_factor / 100.0f);
3614 float EVmin = CLAMP(log2f(black / grey), -16.0f, -1.0f);
3615 EVmin *= (1.0f +
p->security_factor / 100.0f);
3617 p->black_point_source = fmaxf(EVmin, -16.0f);
3618 p->white_point_source = EVmax;
3619 p->output_power = logf(
p->grey_point_target / 100.0f)
3620 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3627 (
void *)picker, (
void *)pipe,
3634 if(picker ==
g->grey_point_source)
3636 else if(picker ==
g->black_point_source)
3638 else if(picker ==
g->white_point_source)
3640 else if(picker ==
g->auto_button)
3648 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off),
TRUE);
3655 g->show_mask = !(
g->show_mask);
3660 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_highlight_mask),
g->show_mask);
3675 const float transition_x,
const float transition_y,
3676 const float slope,
const float power)
3678 const float projected_rise = slope * fmaxf(1e-6f, limit_x - transition_x);
3679 const float actual_rise = fmaxf(1e-6f, limit_y - transition_y);
3680 const float base = fmaxf(1e-6f, powf(actual_rise, -power) - powf(projected_rise, -power));
3681 return fminf(1e9f, powf(base, -1.f / power));
3689 float grey_display = 0.4638f;
3690 gboolean clamping =
FALSE;
3695 grey_display = powf(CLAMP(
p->grey_point_target,
p->black_point_target,
p->white_point_target) / 100.0f,
3696 1.0f / (
p->output_power));
3701 grey_display = powf(0.1845f, 1.0f / (
p->output_power));
3704 const float white_source =
p->white_point_source;
3705 const float black_source =
p->black_point_source;
3706 const float dynamic_range = white_source - black_source;
3709 const float black_log = 0.0f;
3710 const float grey_log = fabsf(
p->black_point_source) / dynamic_range;
3711 const float white_log = 1.0f;
3714 float black_display, white_display;
3722 black_display = CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f;
3723 white_display = fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f;
3728 black_display = powf(CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f,
3729 1.0f / (
p->output_power));
3731 = powf(fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f, 1.0f / (
p->output_power));
3734 float toe_log, shoulder_log, toe_display, shoulder_display, contrast;
3735 float balance = CLAMP(
p->balance, -50.0f, 50.0f) / 100.0f;
3738 float latitude = CLAMP(
p->latitude, 0.0f, 100.0f) / 100.0f * dynamic_range;
3739 contrast = CLAMP(
p->contrast, 1.00001f, 6.0f);
3743 toe_log = grey_log - latitude / dynamic_range * fabsf(black_source / dynamic_range);
3744 shoulder_log = grey_log + latitude / dynamic_range * fabsf(white_source / dynamic_range);
3747 float linear_intercept = grey_display - (contrast * grey_log);
3750 toe_display = (toe_log * contrast + linear_intercept);
3751 shoulder_display = (shoulder_log * contrast + linear_intercept);
3754 const float norm = sqrtf(contrast * contrast + 1.0f);
3757 const float coeff = -((2.0f * latitude) / dynamic_range) * balance;
3759 toe_display +=
coeff * contrast / norm;
3760 shoulder_display +=
coeff * contrast / norm;
3761 toe_log +=
coeff / norm;
3762 shoulder_log +=
coeff / norm;
3769 clamping =
geometry.contrast_clamped;
3788 spline->
x[0] = black_log;
3789 spline->
x[1] = toe_log;
3790 spline->
x[2] = grey_log;
3791 spline->
x[3] = shoulder_log;
3792 spline->
x[4] = white_log;
3794 spline->
y[0] = black_display;
3795 spline->
y[1] = toe_display;
3796 spline->
y[2] = grey_display;
3797 spline->
y[3] = shoulder_display;
3798 spline->
y[4] = white_display;
3803 spline->
type[0] =
p->shadows;
3804 spline->
type[1] =
p->highlights;
3811 const double Tl = spline->
x[1];
3812 const double Tl2 = Tl * Tl;
3813 const double Tl3 = Tl2 * Tl;
3814 const double Tl4 = Tl3 * Tl;
3816 const double Sl = spline->
x[3];
3817 const double Sl2 = Sl * Sl;
3818 const double Sl3 = Sl2 * Sl;
3819 const double Sl4 = Sl3 * Sl;
3829 spline->
M2[2] = contrast;
3830 spline->
M1[2] = spline->
y[1] - spline->
M2[2] * spline->
x[1];
3831 spline->
M3[2] = 0.f;
3832 spline->
M4[2] = 0.f;
3833 spline->
M5[2] = 0.f;
3851 const float sigmoid_toe_power = 1.5f;
3852 const float sigmoid_slope = spline->
M2[2];
3858 spline->
M3[2] = spline->
y[0];
3859 spline->
M4[2] = spline->
y[4];
3867 const float tx = spline->
x[1];
3868 const float ty = spline->
y[1];
3869 const float y0 = spline->
y[0];
3870 const float dx = fmaxf(1e-6f, tx);
3871 const float dy = fmaxf(1e-6f, ty - y0);
3872 spline->
M1[0] = -
filmic_sigmoid_scale(1.f, 1.f - y0, 1.f - tx, 1.f - ty, sigmoid_slope, sigmoid_toe_power);
3873 spline->
M2[0] = sigmoid_toe_power;
3874 spline->
M4[0] = sigmoid_slope * dx / dy;
3875 spline->
M3[0] = dy / powf(dx, spline->
M4[0]);
3876 spline->
M5[0] = (dy / dx > sigmoid_slope) ? 1.f : 0.f;
3883 Tl4, Tl3, Tl2, Tl, 1.,
3884 4. * Tl3, 3. * Tl2, 2. * Tl, 1., 0.,
3885 12. * Tl2, 6. * Tl, 2., 0., 0. };
3887 double b0[
ORDER_4] = { spline->
y[0], 0., spline->
y[1], spline->
M2[2], 0. };
3891 spline->
M5[0] = b0[0];
3892 spline->
M4[0] = b0[1];
3893 spline->
M3[0] = b0[2];
3894 spline->
M2[0] = b0[3];
3895 spline->
M1[0] = b0[4];
3902 3. * Tl2, 2. * Tl, 1., 0.,
3903 6. * Tl, 2., 0., 0. };
3905 double b0[
ORDER_3] = { spline->
y[0], spline->
y[1], spline->
M2[2], 0. };
3909 spline->
M5[0] = 0.0f;
3910 spline->
M4[0] = b0[0];
3911 spline->
M3[0] = b0[1];
3912 spline->
M2[0] = b0[2];
3913 spline->
M1[0] = b0[3];
3917 const float P1[2] = { black_log, black_display };
3918 const float P0[2] = { toe_log, toe_display };
3919 const float x = P0[0] - P1[0];
3920 const float y = P0[1] - P1[1];
3921 const float g = contrast;
3922 const float b =
g / (2.f * y) + (sqrtf(sqf(
x *
g / y + 1.f) - 4.f) - 1.f) / (2.f *
x);
3923 const float c = y /
g * (b * sqf(
x) +
x) / (b * sqf(
x) +
x - (y /
g));
3924 const float a = c *
g;
3928 spline->
M4[0] = toe_display;
3941 const float sx = spline->
x[3];
3942 const float sy = spline->
y[3];
3943 const float y4 = spline->
y[4];
3944 const float dx = fmaxf(1e-6f, 1.f - sx);
3945 const float dy = fmaxf(1e-6f, y4 - sy);
3946 spline->
M4[1] = sigmoid_slope * dx / dy;
3947 spline->
M3[1] = dy / powf(dx, spline->
M4[1]);
3948 spline->
M5[1] = 1.f;
3955 3. * Sl2, 2. * Sl, 1., 0.,
3956 6. * Sl, 2., 0., 0. };
3958 double b1[
ORDER_3] = { spline->
y[4], spline->
y[3], spline->
M2[2], 0. };
3962 spline->
M5[1] = 0.0f;
3963 spline->
M4[1] = b1[0];
3964 spline->
M3[1] = b1[1];
3965 spline->
M2[1] = b1[2];
3966 spline->
M1[1] = b1[3];
3973 Sl4, Sl3, Sl2, Sl, 1.,
3974 4. * Sl3, 3. * Sl2, 2. * Sl, 1., 0.,
3975 12. * Sl2, 6. * Sl, 2., 0., 0. };
3977 double b1[
ORDER_4] = { spline->
y[4], 0., spline->
y[3], spline->
M2[2], 0. };
3981 spline->
M5[1] = b1[0];
3982 spline->
M4[1] = b1[1];
3983 spline->
M3[1] = b1[2];
3984 spline->
M2[1] = b1[3];
3985 spline->
M1[1] = b1[4];
3989 const float P1[2] = { white_log, white_display };
3990 const float P0[2] = { shoulder_log, shoulder_display };
3991 const float x = P1[0] - P0[0];
3992 const float y = P1[1] - P0[1];
3993 const float g = contrast;
3994 const float b =
g / (2.f * y) + (sqrtf(sqf(
x *
g / y + 1.f) - 4.f) - 1.f) / (2.f *
x);
3995 const float c = y /
g * (b * sqf(
x) +
x) / (b * sqf(
x) +
x - (y /
g));
3996 const float a = c *
g;
4000 spline->
M4[1] = shoulder_display;
4012 float grey_source = 0.1845f, grey_display = 0.4638f;
4016 grey_source =
p->grey_point_source / 100.0f;
4017 grey_display = powf(
p->grey_point_target / 100.0f, 1.0f / (
p->output_power));
4022 grey_source = 0.1845f;
4023 grey_display = powf(0.1845f, 1.0f / (
p->output_power));
4027 const float white_source =
p->white_point_source;
4028 const float black_source =
p->black_point_source;
4029 const float dynamic_range = white_source - black_source;
4032 const float grey_log = fabsf(
p->black_point_source) / dynamic_range;
4035 float contrast =
p->contrast;
4040 contrast = 1.0001f * grey_display / grey_log;
4044 d->dynamic_range = dynamic_range;
4045 d->black_source = black_source;
4046 d->grey_source = grey_source;
4047 d->output_power =
p->output_power;
4048 d->contrast = contrast;
4049 d->version =
p->version;
4050 d->spline_version =
p->spline_version;
4051 d->preserve_color =
p->preserve_color;
4052 d->high_quality_reconstruction =
p->high_quality_reconstruction;
4053 d->noise_level =
p->noise_level;
4064 memset(
d->softproof_filename, 0,
sizeof(
d->softproof_filename));
4081 d->saturation =
p->saturation / 100.0f;
4083 d->saturation = (2.0f *
p->saturation / 100.0f + 1.0f);
4098 const float agx_axis =
CLAMPF(
p->saturation / 100.0f, -1.f, 1.f);
4099 d->agx_beta_hue = 0.5f * (agx_axis + 1.f);
4101 d->sigma_toe = powf(
d->spline.latitude_min / 3.0f, 2.0f);
4102 d->sigma_shoulder = powf((1.0f -
d->spline.latitude_max) / 3.0f, 2.0f);
4105 d->reconstruct_threshold = powf(2.0f, white_source +
p->reconstruct_threshold) * grey_source;
4106 d->reconstruct_feather = exp2f(12.f /
p->reconstruct_feather);
4109 d->normalize =
d->reconstruct_feather /
d->reconstruct_threshold;
4110 d->reconstruct_structure_vs_texture = (
p->reconstruct_structure_vs_texture / 100.0f + 1.f) / 2.f;
4111 d->reconstruct_bloom_vs_details = (
p->reconstruct_bloom_vs_details / 100.0f + 1.f) / 2.f;
4112 d->reconstruct_grey_vs_color = (
p->reconstruct_grey_vs_color / 100.0f + 1.f) / 2.f;
4122 gint mask_was_shown =
g->show_mask;
4124 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_highlight_mask),
FALSE);
4156 float shoulder = 0.0f;
4173 &
p->latitude, &
p->balance);
4189 const gint page_num = gtk_notebook_page_num(
g->notebook,
g->reconstruct_page);
4191 if(deprecated && page_num >= 0 && gtk_notebook_get_current_page(
g->notebook) == page_num)
4192 gtk_notebook_set_current_page(
g->notebook, 0);
4194 GtkWidget *tab_label = gtk_notebook_get_tab_label(
g->notebook,
g->reconstruct_page);
4195 if(!
IS_NULL_PTR(tab_label)) gtk_widget_set_visible(tab_label, !deprecated);
4196 gtk_widget_set_visible(
g->reconstruct_page, !deprecated);
4208 g->gui_show_labels =
dt_conf_get_int(
"plugins/darkroom/filmicrgb/graph_show_labels");
4210 g->gui_sizes_inited =
FALSE;
4214 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->auto_hardness),
p->auto_hardness);
4215 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->custom_grey),
p->custom_grey);
4227 d->white_point_source =
module->so->get_f("white_point_source")->Float.Default;
4228 d->output_power =
module->so->get_f("output_power")->Float.Default;
4243 d->white_point_source = exposure + 2.45f;
4244 d->black_point_source =
d->white_point_source - 12.f;
4245 d->output_power = logf(
d->grey_point_target / 100.0f)
4246 / logf(-
d->black_point_source / (
d->white_point_source -
d->black_point_source));
4248 module->workflow_enabled = TRUE;
4250 dt_iop_fmt_log(module,
"reload_defaults: class=%s needs_rawprepare=%d -> workflow_enabled=%d white=%.3f black=%.3f",
4253 d->white_point_source,
d->black_point_source);
4259 const int program = 22;
4274 const int wavelets = 35;
4311 double destination_y, gboolean show_head)
4313 cairo_move_to(cr, origin_x, origin_y);
4314 cairo_line_to(cr, destination_x, destination_y);
4320 const float angle_arrow = 45.f / 360.f *
M_PI;
4321 const float angle_trunk = atan2f((destination_y - origin_y), (destination_x - origin_x));
4324 const float x_1 = destination_x + radius / sinf(angle_arrow + angle_trunk);
4325 const float y_1 = destination_y + radius / cosf(angle_arrow + angle_trunk);
4327 const float x_2 = destination_x - radius / sinf(-angle_arrow + angle_trunk);
4328 const float y_2 = destination_y - radius / cosf(-angle_arrow + angle_trunk);
4330 cairo_move_to(cr, x_1, y_1);
4331 cairo_line_to(cr, destination_x, destination_y);
4332 cairo_line_to(cr, x_2, y_2);
4340 if(!
g->gui_sizes_inited)
return;
4370 const float scale = 0.85;
4371 cairo_scale(cr, scale, scale);
4372 button->
icon(cr, -scale * button->
w / 2., -scale * button->
h / 2., scale * button->
w, scale * button->
h, 0, NULL);
4385 gtk_widget_get_allocation(widget, &
g->allocation);
4387 cairo_surface_t *cst =
4389 PangoFontDescription *desc =
4391 cairo_t *cr = cairo_create(cst);
4392 PangoLayout *layout = pango_cairo_create_layout(cr);
4394 pango_layout_set_font_description(layout, desc);
4396 g->context = gtk_widget_get_style_context(widget);
4401 const gint font_size = pango_font_description_get_size(desc);
4402 pango_font_description_set_size(desc, 0.95 * font_size);
4403 pango_layout_set_font_description(layout, desc);
4406 g_strlcpy(text,
"X",
sizeof(text));
4407 pango_layout_set_text(layout, text, -1);
4408 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4409 g->line_height =
g->ink.height;
4412 g_strlcpy(text,
"-",
sizeof(text));
4413 pango_layout_set_text(layout, text, -1);
4414 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4415 g->sign_width =
g->ink.width / 2.0;
4418 g_strlcpy(text,
"0",
sizeof(text));
4419 pango_layout_set_text(layout, text, -1);
4420 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4421 g->zero_width =
g->ink.width;
4427 float margin_bottom;
4428 if(
g->gui_show_labels)
4431 margin_left = 3. *
g->zero_width + 2. *
g->inset;
4432 margin_bottom = 2. *
g->line_height + 4. *
g->inset;
4436 margin_left =
g->inset;
4437 margin_bottom =
g->inset;
4440 const float margin_top = 2. *
g->line_height +
g->inset;
4443 g->graph_width =
g->allocation.width - margin_right - margin_left;
4444 g->graph_height =
g->allocation.height - margin_bottom - margin_top;
4446 gtk_render_background(
g->context, cr, 0, 0,
g->allocation.width,
g->allocation.height);
4452 g->buttons[
i].right =
g->allocation.width;
4456 g->buttons[
i].w =
g->buttons[
i].right -
g->buttons[
i].left;
4457 g->buttons[
i].h =
g->buttons[
i].bottom -
g->buttons[
i].top;
4458 g->buttons[
i].state = GTK_STATE_FLAG_NORMAL;
4461 g->gui_sizes_inited =
TRUE;
4471 const float grey =
p->grey_point_source / 100.f;
4472 const float DR =
p->white_point_source -
p->black_point_source;
4475 cairo_translate(cr, margin_left, margin_top);
4477 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
4480 pango_font_description_set_size(desc, font_size);
4481 pango_layout_set_font_description(layout, desc);
4483 g_strlcpy(text, _(
"look only"),
sizeof(text));
4485 g_strlcpy(text, _(
"look + mapping (lin)"),
sizeof(text));
4487 g_strlcpy(text, _(
"look + mapping (log)"),
sizeof(text));
4489 g_strlcpy(text, _(
"dynamic range mapping"),
sizeof(text));
4491 pango_layout_set_text(layout, text, -1);
4492 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4496 cairo_rectangle(cr,
g->allocation.width - margin_left -
g->ink.width -
g->ink.x - 2. *
g->inset,
4497 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y -
g->inset,
4498 g->ink.width + 3. *
g->inset,
g->ink.height + 2. *
g->inset);
4503 cairo_move_to(cr,
g->allocation.width - margin_left -
g->ink.width -
g->ink.x -
g->inset,
4504 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y);
4505 pango_cairo_show_layout(cr, layout);
4509 pango_font_description_set_size(desc, 0.95 * font_size);
4510 pango_layout_set_font_description(layout, desc);
4516 cairo_rectangle(cr, 0, 0,
g->graph_width,
g->graph_height);
4518 cairo_fill_preserve(cr);
4528 cairo_scale(cr, 1., -1.);
4529 cairo_translate(cr, 0., -
g->graph_height);
4540 cairo_move_to(cr, 0,
g->graph_height);
4541 cairo_line_to(cr,
g->graph_width, 0);
4547 const float saturation = (2.0f *
p->saturation / 100.0f + 1.0f);
4548 const float sigma_toe = powf(
g->spline.latitude_min / 3.0f, 2.0f);
4549 const float sigma_shoulder = powf((1.0f -
g->spline.latitude_max) / 3.0f, 2.0f);
4551 cairo_set_source_rgb(cr, .5, .5, .5);
4561 cairo_move_to(cr, 0,
4562 g->graph_height * (1.0 - filmic_desaturate_v1(0.0f, sigma_toe, sigma_shoulder, saturation)));
4563 for(
int k = 1;
k < 256;
k++)
4565 float x =
k / 255.0;
4566 const float y = filmic_desaturate_v1(
x, sigma_toe, sigma_shoulder, saturation);
4573 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4578 cairo_move_to(cr, 0,
4579 g->graph_height * (1.0 - filmic_desaturate_v2(0.0f, sigma_toe, sigma_shoulder, saturation)));
4580 for(
int k = 1;
k < 256;
k++)
4582 float x =
k / 255.0;
4583 const float y = filmic_desaturate_v2(
x, sigma_toe, sigma_shoulder, saturation);
4590 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4596 float x_start = 0.f;
4602 float y_start =
clamp_simd(filmic_spline(x_start,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
4603 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type));
4606 y_start = powf(y_start,
p->output_power);
4610 cairo_move_to(cr, 0,
g->graph_height * (1.0 - y_start));
4612 for(
int k = 1;
k < 256;
k++)
4616 float x = powf(
k / 255.0f, 2.4f);
4624 float y = filmic_spline(
value,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
g->spline.M5,
4625 g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
4633 const float margin = 1
E-5;
4634 if(y >
g->spline.y[4] + margin)
4637 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4639 else if(y < g->spline.
y[0] - margin)
4642 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4650 y = powf(y,
p->output_power);
4654 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4656 cairo_move_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4668 float x_grey =
g->spline.x[2];
4669 float y_grey =
g->spline.y[2];
4674 y_grey = powf(y_grey,
p->output_power);
4682 cairo_set_source_rgb(cr, 0.75, 0.5, 0.0);
4683 cairo_arc(cr, x_grey *
g->graph_width, (1.0 - y_grey) *
g->graph_height,
DT_PIXEL_APPLY_DPI(6), 0,
4689 float x_black = 0.f;
4690 float y_black = 0.f;
4692 float x_white = 1.f;
4693 float y_white = 1.f;
4695 const float central_slope = (
g->spline.y[3] -
g->spline.y[1]) *
g->graph_width / ((
g->spline.x[3] -
g->spline.x[1]) *
g->graph_height);
4696 const float central_slope_angle = atanf(central_slope) +
M_PI / 2.0f;
4698 for(
int k = 0;
k < 5;
k++)
4702 float x =
g->spline.x[
k];
4703 float y =
g->spline.y[
k];
4704 const float ymin =
g->spline.y[0];
4705 const float ymax =
g->spline.y[4];
4707 const float y_margin =
SAFETY_MARGIN * 1.1f * (ymax - ymin);
4708 gboolean red = (((
k == 1) && (y - ymin <= y_margin))
4709 || ((
k == 3) && (ymax - y <= y_margin)));
4710 float start_angle = 0.0f;
4711 float end_angle = 2.f *
M_PI;
4714 if(contrast_clamped)
4718 start_angle = central_slope_angle +
M_PI;
4719 end_angle = central_slope_angle;
4723 start_angle = central_slope_angle;
4724 end_angle = start_angle +
M_PI;
4731 y = powf(y,
p->output_power);
4751 if(red) cairo_set_source_rgb(cr, 0.8, 0.35, 0.35);
4754 cairo_arc(cr,
x *
g->graph_width, (1.0 - y) *
g->graph_height,
DT_PIXEL_APPLY_DPI(4), start_angle, end_angle);
4764 if(
g->gui_show_labels)
4767 const float x_legend_top =
g->graph_height + 0.5 *
g->line_height;
4771 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_target);
4772 pango_layout_set_text(layout, text, -1);
4773 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4774 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4775 (1.0 - y_grey) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4776 pango_cairo_show_layout(cr, layout);
4782 snprintf(text,
sizeof(text),
"%+.1f", 0.f);
4784 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_source);
4786 pango_layout_set_text(layout, text, -1);
4787 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4788 cairo_move_to(cr, x_grey *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x, x_legend_top);
4789 pango_cairo_show_layout(cr, layout);
4794 snprintf(text,
sizeof(text),
"%.0f",
p->black_point_target);
4795 pango_layout_set_text(layout, text, -1);
4796 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4797 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4798 (1.0 - y_black) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4799 pango_cairo_show_layout(cr, layout);
4804 snprintf(text,
sizeof(text),
"%.0f",
p->white_point_target);
4805 pango_layout_set_text(layout, text, -1);
4806 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4807 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4808 (1.0 - y_white) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4809 pango_cairo_show_layout(cr, layout);
4815 snprintf(text,
sizeof(text),
"%+.1f",
p->black_point_source);
4817 snprintf(text,
sizeof(text),
"%.0f", exp2f(
p->black_point_source) *
p->grey_point_source);
4819 pango_layout_set_text(layout, text, -1);
4820 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4821 cairo_move_to(cr, x_black *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x, x_legend_top);
4822 pango_cairo_show_layout(cr, layout);
4828 snprintf(text,
sizeof(text),
"%+.1f",
p->white_point_source);
4832 snprintf(text,
sizeof(text),
"%.0f \342\206\222", 100.f);
4834 snprintf(text,
sizeof(text),
"%.0f", exp2f(
p->white_point_source) *
p->grey_point_source);
4837 pango_layout_set_text(layout, text, -1);
4838 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4840 fminf(x_white, 1.f) *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x
4841 + 2. * (x_white > 1.f) *
g->sign_width,
4843 pango_cairo_show_layout(cr, layout);
4852 PangoStyle backup = pango_font_description_get_style(desc);
4853 pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
4854 pango_layout_set_font_description(layout, desc);
4856 snprintf(text,
sizeof(text), _(
"(%.0f %%)"), exp2f(
p->white_point_source) *
p->grey_point_source);
4857 pango_layout_set_text(layout, text, -1);
4858 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4859 cairo_move_to(cr,
g->allocation.width -
g->ink.width -
g->ink.x - margin_left,
4860 g->graph_height + 3. *
g->inset +
g->line_height -
g->ink.y);
4861 pango_cairo_show_layout(cr, layout);
4865 pango_font_description_set_style(desc, backup);
4866 pango_layout_set_font_description(layout, desc);
4872 g_strlcpy(text, _(
"% display"),
sizeof(text));
4873 pango_layout_set_text(layout, text, -1);
4874 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4875 cairo_move_to(cr, -2. *
g->inset -
g->zero_width -
g->ink.x,
4876 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y);
4877 pango_cairo_show_layout(cr, layout);
4884 g_strlcpy(text, _(
"EV scene"),
sizeof(text));
4888 g_strlcpy(text, _(
"% camera"),
sizeof(text));
4890 pango_layout_set_text(layout, text, -1);
4891 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4892 cairo_move_to(cr, 0.5 *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x,
4893 g->graph_height + 3. *
g->inset +
g->line_height -
g->ink.y);
4894 pango_cairo_show_layout(cr, layout);
4901 cairo_identity_matrix(cr);
4907 const float display_DR = 12.f + log2f(
p->white_point_target / 100.f);
4909 const float y_display =
g->allocation.height / 3.f +
g->line_height;
4910 const float y_scene = 2. *
g->allocation.height / 3.f +
g->line_height;
4912 const float display_top = y_display -
g->line_height / 2;
4913 const float display_bottom = display_top +
g->line_height;
4915 const float scene_top = y_scene -
g->line_height / 2;
4916 const float scene_bottom = scene_top +
g->line_height;
4920 if(
g->gui_show_labels)
4924 g_strlcpy(text, _(
"display"),
sizeof(text));
4925 pango_layout_set_text(layout, text, -1);
4926 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4927 cairo_move_to(cr, 0., y_display - 0.5 *
g->ink.height -
g->ink.y);
4928 pango_cairo_show_layout(cr, layout);
4930 const float display_label_width =
g->ink.width;
4933 g_strlcpy(text, _(
"(%)"),
sizeof(text));
4934 pango_layout_set_text(layout, text, -1);
4935 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4936 cairo_move_to(cr, 0.5 * display_label_width - 0.5 *
g->ink.width -
g->ink.x,
4937 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
4938 pango_cairo_show_layout(cr, layout);
4942 g_strlcpy(text, _(
"scene"),
sizeof(text));
4943 pango_layout_set_text(layout, text, -1);
4944 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4945 cairo_move_to(cr, 0., y_scene - 0.5 *
g->ink.height -
g->ink.y);
4946 pango_cairo_show_layout(cr, layout);
4948 const float scene_label_width =
g->ink.width;
4951 g_strlcpy(text, _(
"(EV)"),
sizeof(text));
4952 pango_layout_set_text(layout, text, -1);
4953 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4954 cairo_move_to(cr, 0.5 * scene_label_width - 0.5 *
g->ink.width -
g->ink.x,
4955 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
4956 pango_cairo_show_layout(cr, layout);
4961 dt_cairo_draw_arrow(cr, fminf(scene_label_width, display_label_width) / 2.f, y_scene -
g->line_height,
4962 fminf(scene_label_width, display_label_width) / 2.f,
4963 y_display +
g->line_height +
g->inset,
TRUE);
4965 column_left = fmaxf(display_label_width, scene_label_width) +
g->inset;
4973 const float display_HL_EV = -log2f(
p->grey_point_target /
p->white_point_target);
4974 const float display_LL_EV = display_DR - display_HL_EV;
4975 const float display_real_black_EV
4976 = -fmaxf(log2f(
p->black_point_target /
p->grey_point_target),
4977 -11.685887601778058f + display_HL_EV - log2f(
p->white_point_target / 100.f));
4978 const float scene_HL_EV =
p->white_point_source;
4979 const float scene_LL_EV = -
p->black_point_source;
4982 const float max_DR = ceilf(fmaxf(display_HL_EV, scene_HL_EV)) + ceilf(fmaxf(display_LL_EV, scene_LL_EV));
4983 const float EV = (column_right) / max_DR;
4987 const float grey_EV = fmaxf(ceilf(display_HL_EV), ceilf(scene_HL_EV));
4991 const float display_black_x = grey_x - display_real_black_EV * EV;
4992 const float display_DR_start_x = grey_x - display_LL_EV * EV;
4993 const float display_white_x = grey_x + display_HL_EV * EV;
4995 const float scene_black_x = grey_x - scene_LL_EV * EV;
4996 const float scene_white_x = grey_x + scene_HL_EV * EV;
4997 const float scene_lat_bottom = grey_x + (
g->spline.x[1] -
g->spline.x[2]) * EV * DR;
4998 const float scene_lat_top = grey_x + (
g->spline.x[3] -
g->spline.x[2]) * EV * DR;
5006 float display_lat_bottom = filmic_spline(
g->spline.latitude_min,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
5007 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
5008 display_lat_bottom = powf(fmaxf(display_lat_bottom,
NORM_MIN),
p->output_power);
5011 display_lat_bottom = log2f(display_lat_bottom/ (
p->grey_point_target / 100.f));
5014 if(display_lat_bottom < 0.f)
5015 display_lat_bottom = fmaxf(display_lat_bottom, -display_real_black_EV);
5016 else if(display_lat_bottom > 0.f)
5017 display_lat_bottom = fminf(display_lat_bottom, display_HL_EV);
5020 display_lat_bottom = grey_x + display_lat_bottom * EV;
5023 float display_lat_top = filmic_spline(
g->spline.latitude_max,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
5024 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
5025 display_lat_top = powf(fmaxf(display_lat_top,
NORM_MIN),
p->output_power);
5028 display_lat_top = log2f(display_lat_top / (
p->grey_point_target / 100.f));
5031 if(display_lat_top < 0.f)
5032 display_lat_top = fmaxf(display_lat_top, -display_real_black_EV);
5033 else if(display_lat_top > 0.f)
5034 display_lat_top = fminf(display_lat_top, display_HL_EV);
5037 display_lat_top = grey_x + display_lat_top * EV;
5039 cairo_move_to(cr, scene_lat_bottom, scene_top);
5040 cairo_line_to(cr, scene_lat_top, scene_top);
5041 cairo_line_to(cr, display_lat_top, display_bottom);
5042 cairo_line_to(cr, display_lat_bottom, display_bottom);
5043 cairo_line_to(cr, scene_lat_bottom, scene_top);
5047 for(
int i = 0;
i < (int)ceilf(display_DR);
i++)
5050 const float shade = powf(exp2f(-11.f + (
float)
i), 1.f / 2.4f);
5051 cairo_set_source_rgb(cr, shade, shade, shade);
5052 cairo_rectangle(cr, display_DR_start_x +
i * EV, display_top, EV,
g->line_height);
5053 cairo_fill_preserve(cr);
5056 cairo_set_source_rgb(cr, 0.75, .5, 0.);
5062 cairo_move_to(cr, grey_x, display_bottom + 2. *
g->inset);
5063 cairo_line_to(cr, grey_x, display_top - 2. *
g->inset);
5068 for(
int i = floorf(
p->black_point_source);
i < ceilf(
p->white_point_source);
i++)
5072 const float shade = powf(0.1845f * exp2f((
float)
i), 1.f / 2.4f);
5073 const float x_temp = grey_x +
i * EV;
5074 cairo_set_source_rgb(cr, shade, shade, shade);
5075 cairo_rectangle(cr, x_temp, scene_top, EV,
g->line_height);
5076 cairo_fill_preserve(cr);
5079 cairo_set_source_rgb(cr, 0.75, .5, 0.);
5088 if((
float)
i >
p->black_point_source && (
float)i < p->white_point_source)
5091 const float normal_value = ((float)
i -
p->black_point_source) / DR;
5092 float y_temp = filmic_spline(normal_value,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
5093 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
5094 y_temp = powf(fmaxf(y_temp,
NORM_MIN),
p->output_power);
5097 y_temp = log2f(y_temp / (
p->grey_point_target / 100.f));
5101 y_temp = fmaxf(y_temp, -display_real_black_EV);
5102 else if(y_temp > 0.f)
5103 y_temp = fminf(y_temp, display_HL_EV);
5106 y_temp = grey_x + y_temp * EV;
5114 float x_temp = grey_x +
p->black_point_source * EV;
5115 float y_temp = grey_x - display_real_black_EV * EV;
5118 x_temp = grey_x +
p->white_point_source * EV;
5119 y_temp = grey_x + display_HL_EV * EV;
5125 cairo_move_to(cr, display_black_x, display_bottom);
5126 cairo_line_to(cr, display_black_x, display_top - 2. *
g->inset);
5130 cairo_move_to(cr, grey_x, display_bottom);
5131 cairo_line_to(cr, grey_x, display_top - 2. *
g->inset);
5135 cairo_move_to(cr, display_white_x, display_bottom);
5136 cairo_line_to(cr, display_white_x, display_top - 2. *
g->inset);
5140 cairo_move_to(cr, scene_black_x, scene_bottom + 2. *
g->inset);
5141 cairo_line_to(cr, scene_black_x, scene_top);
5145 cairo_move_to(cr, grey_x, scene_bottom + 2. *
g->inset);
5146 cairo_line_to(cr, grey_x, scene_top);
5150 cairo_move_to(cr, scene_white_x, scene_bottom + 2. *
g->inset);
5151 cairo_line_to(cr, scene_white_x, scene_top);
5158 snprintf(text,
sizeof(text),
"%+.1f",
p->black_point_source);
5159 pango_layout_set_text(layout, text, -1);
5160 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5161 cairo_move_to(cr, scene_black_x - 0.5 *
g->ink.width -
g->ink.x,
5162 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5163 pango_cairo_show_layout(cr, layout);
5167 snprintf(text,
sizeof(text),
"%+.1f", 0.f);
5168 pango_layout_set_text(layout, text, -1);
5169 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5170 cairo_move_to(cr, grey_x - 0.5 *
g->ink.width -
g->ink.x,
5171 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5172 pango_cairo_show_layout(cr, layout);
5176 snprintf(text,
sizeof(text),
"%+.1f",
p->white_point_source);
5177 pango_layout_set_text(layout, text, -1);
5178 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5179 cairo_move_to(cr, scene_white_x - 0.5 *
g->ink.width -
g->ink.x,
5180 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5181 pango_cairo_show_layout(cr, layout);
5185 snprintf(text,
sizeof(text),
"%.0f",
p->black_point_target);
5186 pango_layout_set_text(layout, text, -1);
5187 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5188 cairo_move_to(cr, display_black_x - 0.5 *
g->ink.width -
g->ink.x,
5189 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5190 pango_cairo_show_layout(cr, layout);
5194 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_target);
5195 pango_layout_set_text(layout, text, -1);
5196 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5197 cairo_move_to(cr, grey_x - 0.5 *
g->ink.width -
g->ink.x,
5198 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5199 pango_cairo_show_layout(cr, layout);
5203 snprintf(text,
sizeof(text),
"%.0f",
p->white_point_target);
5204 pango_layout_set_text(layout, text, -1);
5205 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5206 cairo_move_to(cr, display_white_x - 0.5 *
g->ink.width -
g->ink.x,
5207 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5208 pango_cairo_show_layout(cr, layout);
5213 pango_font_description_set_size(desc, font_size);
5214 pango_layout_set_font_description(layout, desc);
5217 cairo_set_source_surface(crf, cst, 0, 0);
5219 cairo_surface_destroy(cst);
5220 g_object_unref(layout);
5221 pango_font_description_free(desc);
5237 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
5243 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5252 else if(event->button == 1)
5263 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5269 g->gui_show_labels = !
g->gui_show_labels;
5270 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5271 dt_conf_set_int(
"plugins/darkroom/filmicrgb/graph_show_labels",
g->gui_show_labels);
5281 else if(event->button == 3)
5291 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5297 g->gui_show_labels = !
g->gui_show_labels;
5298 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5299 dt_conf_set_int(
"plugins/darkroom/filmicrgb/graph_show_labels",
g->gui_show_labels);
5319 g->gui_hover =
TRUE;
5320 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5333 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5343 if(!
g->gui_sizes_inited)
return FALSE;
5346 const float y =
event->y;
5347 const float x =
event->x;
5349 if(
x > 0. && x < g->allocation.width && y > 0. && y < g->allocation.height)
g->gui_hover =
TRUE;
5351 gint save_active_button =
g->active_button;
5356 gint found_something =
FALSE;
5360 if(
x >
g->buttons[
i].left && x < g->buttons[
i].right && y >
g->buttons[
i].top && y < g->buttons[
i].bottom)
5363 g->buttons[
i].mouse_hover =
TRUE;
5364 g->active_button =
i;
5365 found_something =
TRUE;
5370 g->buttons[
i].mouse_hover =
FALSE;
5380 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"use the parameters below to set the nodes.\n"
5381 "the bright curve is the filmic tone mapping curve\n"
5382 "the dark curve is the desaturation curve."));
5386 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"toggle axis labels and values display"));
5390 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"cycle through graph views.\n"
5391 "left click: cycle forward.\n"
5392 "right click: cycle backward.\n"
5393 "double-click: reset to look view."));
5397 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area),
"");
5400 if(save_active_button !=
g->active_button) gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5406 if(save_active_button !=
g->active_button) (GTK_WIDGET(
g->area));
5423 g->gui_show_labels =
TRUE;
5425 g->gui_sizes_inited =
FALSE;
5428 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
5429 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
5430 g_object_set_data(G_OBJECT(
g->area),
"iop-instance", self);
5432 gtk_widget_set_can_focus(GTK_WIDGET(
g->area),
TRUE);
5433 gtk_widget_add_events(GTK_WIDGET(
g->area), GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
5436 g_signal_connect(G_OBJECT(
g->area),
"button-press-event", G_CALLBACK(
area_button_press), self);
5437 g_signal_connect(G_OBJECT(
g->area),
"leave-notify-event", G_CALLBACK(
area_leave_notify), self);
5438 g_signal_connect(G_OBJECT(
g->area),
"enter-notify-event", G_CALLBACK(
area_enter_notify), self);
5439 g_signal_connect(G_OBJECT(
g->area),
"motion-notify-event", G_CALLBACK(
area_motion_notify), self);
5452 g->grey_point_source
5456 gtk_widget_set_tooltip_text(
g->grey_point_source,
5457 _(
"adjust to match the average luminance of the image's subject.\n"
5458 "the value entered here will then be remapped to 18.45%.\n"
5459 "decrease the value to increase the overall brightness."));
5462 g->white_point_source
5466 gtk_widget_set_tooltip_text(
g->white_point_source,
5467 _(
"number of stops between middle gray and pure white.\n"
5468 "this is a reading a lightmeter would give you on the scene.\n"
5469 "adjust so highlights clipping is avoided"));
5472 g->black_point_source
5476 gtk_widget_set_tooltip_text(
5477 g->black_point_source, _(
"number of stops between middle gray and pure black.\n"
5478 "this is a reading a lightmeter would give you on the scene.\n"
5479 "increase to get more contrast.\ndecrease to recover more details in low-lights."));
5485 gtk_widget_set_tooltip_text(
g->security_factor, _(
"symmetrically enlarge or shrink the computed dynamic range.\n"
5486 "useful to give a safety margin to extreme luminances."));
5492 gtk_box_pack_start(GTK_BOX(hbox),
g->auto_button,
FALSE,
FALSE, 0);
5494 gtk_widget_set_tooltip_text(
g->auto_button, _(
"try to optimize the settings with some statistical assumptions.\n"
5495 "this will fit the luminance range inside the histogram bounds.\n"
5496 "works better for landscapes and evenly-lit pictures\n"
5497 "but fails for high-keys, low-keys and high-ISO pictures.\n"
5498 "this is not an artificial intelligence, but a simple guess.\n"
5499 "ensure you understand its assumptions before using it."));
5506 gtk_widget_set_tooltip_text(
g->custom_grey, _(
"enable to input custom middle-gray values.\n"
5507 "this is not recommended in general.\n"
5508 "fix the global exposure in the exposure module instead.\n"
5509 "disable to use standard 18.45 %% middle gray."));
5521 gtk_widget_set_tooltip_text(
g->reconstruct_threshold,
5522 _(
"set the exposure threshold upon which\n"
5523 "clipped highlights get reconstructed.\n"
5524 "values are relative to the scene white point.\n"
5525 "0 EV means the threshold is the same as the scene white point.\n"
5526 "decrease to include more areas,\n"
5527 "increase to exclude more areas."));
5531 gtk_widget_set_tooltip_text(
g->reconstruct_feather,
5532 _(
"soften the transition between clipped highlights and valid pixels.\n"
5533 "decrease to make the transition harder and sharper,\n"
5534 "increase to make the transition softer and blurrier."));
5538 gtk_box_pack_start(GTK_BOX(hbox),
dt_ui_label_new(_(
"display highlight reconstruction mask")),
TRUE,
TRUE, 0);
5551 gtk_widget_set_tooltip_text(
g->reconstruct_structure_vs_texture,
5553 _(
"decide which reconstruction strategy to favor,\n"
5554 "between inpainting a smooth color gradient,\n"
5555 "or trying to recover the textured details.\n"
5556 "0% is an equal mix of both.\n"
5557 "increase if at least one RGB channel is not clipped.\n"
5558 "decrease if all RGB channels are clipped over large areas."));
5562 gtk_widget_set_tooltip_text(
g->reconstruct_bloom_vs_details,
5564 _(
"decide which reconstruction strategy to favor,\n"
5565 "between blooming highlights like film does,\n"
5566 "or trying to recover sharp details.\n"
5567 "0% is an equal mix of both.\n"
5568 "increase if you want more details.\n"
5569 "decrease if you want more blur."));
5574 gtk_widget_set_tooltip_text(
g->reconstruct_grey_vs_color,
5576 _(
"decide which reconstruction strategy to favor,\n"
5577 "between recovering monochromatic highlights,\n"
5578 "or trying to recover colorful highlights.\n"
5579 "0% is an equal mix of both.\n"
5580 "increase if you want more color.\n"
5581 "decrease if you see magenta or out-of-gamut highlights."));
5588 gtk_widget_set_tooltip_text(
g->high_quality_reconstruction,
5589 _(
"run extra passes of chromaticity reconstruction.\n"
5590 "more iterations means more color propagation from neighbourhood.\n"
5591 "this will be slower but will yield more neutral highlights.\n"
5592 "it also helps with difficult cases of magenta highlights."));
5596 gtk_widget_set_tooltip_text(
g->noise_level, _(
"add statistical noise in reconstructed highlights.\n"
5597 "this avoids highlights to look too smooth\n"
5598 "when the picture is noisy overall,\n"
5599 "so they blend with the rest of the picture."));
5603 gtk_widget_set_tooltip_text(
g->noise_distribution, _(
"choose the statistical distribution of noise.\n"
5604 "this is useful to match natural sensor noise pattern.\n"));
5615 gtk_widget_set_tooltip_text(
g->contrast, _(
"slope of the linear part of the curve\n"
5616 "affects mostly the mid-tones"));
5620 gtk_widget_set_tooltip_text(
g->output_power, _(
"equivalent to paper grade in analog.\n"
5621 "increase to make highlights brighter and less compressed.\n"
5622 "decrease to mute highlights."));
5633 gtk_widget_set_tooltip_text(
g->shoulder,
5634 _(
"distance between middle gray and the start of the highlights roll-off.\n"
5635 "0% keeps the shoulder at middle gray, 100% pushes it to the point where the\n"
5636 "current slope would hit the output white level."));
5644 gtk_widget_set_tooltip_text(
g->toe,
5645 _(
"distance between middle gray and the start of the shadows roll-off.\n"
5646 "0% keeps the toe at middle gray, 100% pushes it to the point where the\n"
5647 "current slope would hit the output black level."));
5652 gtk_widget_set_tooltip_text(
g->highlights, _(
"shape of the highlights roll-off of the curve.\n"
5653 "perceptual (default) is a generalized sigmoid derived from a\n"
5654 "perceptual appearance model: always smooth and monotonic.\n"
5655 "hard/soft/safe are the legacy polynomial/rational segments;\n"
5656 "hard compresses highlights more, soft less."));
5659 gtk_widget_set_tooltip_text(
g->shadows, _(
"shape of the shadows roll-off of the curve.\n"
5660 "perceptual (default) is a generalized sigmoid derived from a\n"
5661 "perceptual appearance model: always smooth and monotonic.\n"
5662 "hard/soft/safe are the legacy polynomial/rational segments;\n"
5663 "hard compresses shadows more, soft less."));
5671 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5672 "specifically at extreme luminances.\n"
5673 "increase if shadows and/or highlights are under-saturated."));
5676 gtk_widget_set_tooltip_text(
g->preserve_color, _(
"ensure the original color are preserved.\n"
5677 "may reinforce chromatic aberrations and chroma noise,\n"
5678 "so ensure they are properly corrected elsewhere.\n"));
5685 gtk_widget_set_tooltip_text(
g->version,
5686 _(
"v3 is darktable 3.0 desaturation method, same as color balance.\n"
5687 "v4 is a newer desaturation method, based on spectral purity of light.\n"
5688 "v8 tone maps each RGB channel separately in an inset rendering space:\n"
5689 "highlights bleach toward white and hues drift as tonal compression\n"
5690 "increases, with a parametric hue recovery on the saturation slider."));
5695 gtk_widget_set_tooltip_text(
g->spline_version,
5696 _(
"how the latitude, balance and contrast place the toe and\n"
5697 "shoulder nodes of the curve (not the shape between them —\n"
5698 "that is 'contrast in shadows/highlights').\n"
5699 "v3 (2021) is recommended; v1/v2 are kept for older edits."));
5703 gtk_widget_set_tooltip_text(
5704 g->auto_hardness, _(
"enable to auto-set the look hardness depending on the scene white and black points.\n"
5705 "this keeps the middle gray on the identity line and improves fast tuning.\n"
5706 "disable if you want a manual control."));
5715 gtk_widget_set_tooltip_text(
g->black_point_target, _(
"luminance of output pure black, "
5716 "this should be 0%\nexcept if you want a faded look"));
5721 gtk_widget_set_tooltip_text(
g->grey_point_target,
5722 _(
"middle gray value of the target display or color space.\n"
5723 "you should never touch that unless you know what you are doing."));
5729 gtk_widget_set_tooltip_text(
g->white_point_target, _(
"luminance of output pure white, "
5730 "this should be 100%\nexcept if you want a faded look"));
5735 gtk_box_pack_start(GTK_BOX(self->
gui->
widget),
5737 "plugins/darkroom/filmicrgb/graphheight", 230, 100),
5747 if(
IS_NULL_PTR(w) || w ==
g->auto_hardness || w ==
g->security_factor || w ==
g->grey_point_source
5748 || w ==
g->black_point_source || w ==
g->white_point_source)
5752 if(w ==
g->security_factor || w ==
g->grey_point_source)
5754 float prev = *(
float *)previous;
5755 if(w ==
g->security_factor)
5757 float ratio = (
p->security_factor - prev) / (prev + 100.0f);
5759 float EVmin =
p->black_point_source;
5760 EVmin = EVmin + ratio * EVmin;
5762 float EVmax =
p->white_point_source;
5763 EVmax = EVmax + ratio * EVmax;
5765 p->white_point_source = EVmax;
5766 p->black_point_source = EVmin;
5770 float grey_var = log2f(prev /
p->grey_point_source);
5771 p->black_point_source =
p->black_point_source - grey_var;
5772 p->white_point_source =
p->white_point_source + grey_var;
5779 if(
p->auto_hardness)
5780 p->output_power = logf(
p->grey_point_target / 100.0f)
5781 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
5783 gtk_widget_set_visible(GTK_WIDGET(
g->output_power), !
p->auto_hardness);
5794 gtk_widget_set_tooltip_text(
g->saturation, _(
"how much of the per-channel hue drift to keep.\n"
5795 "saturation is not affected: valid diffuse colors\n"
5796 "(skin tones, product colors) keep their saturation and\n"
5797 "strongly compressed colors bleach, at any setting.\n"
5798 "-100%% is pure AgX: full hue drift (the 'film' look).\n"
5799 "0%% (default) removes half the hue drift.\n"
5800 "+100%% restores the original hues exactly."));
5801 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
FALSE);
5806 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5807 "specifically at extreme luminances.\n"
5808 "increase if shadows and/or highlights are under-saturated."));
5813 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5814 "specifically at medium luminances.\n"
5815 "increase if midtones are under-saturated."));
5820 gtk_widget_set_tooltip_text(
g->saturation, _(
"Positive values ensure saturation is kept unchanged over the whole range.\n"
5821 "Negative values bleache highlights at constant hue and luminance.\n"
5822 "Zero is an equal mix of both strategies."));
5823 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
FALSE);
5828 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
TRUE);
5831 if(
IS_NULL_PTR(w) || w ==
g->reconstruct_bloom_vs_details)
5833 if(
p->reconstruct_bloom_vs_details == -100.f)
5838 gtk_widget_set_sensitive(
g->reconstruct_structure_vs_texture,
FALSE);
5842 gtk_widget_set_sensitive(
g->reconstruct_structure_vs_texture,
TRUE);
5848 gtk_widget_set_visible(
g->grey_point_source,
p->custom_grey);
5849 gtk_widget_set_visible(
g->grey_point_target,
p->custom_grey);
5853 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
void dt_gui_set_pango_resolution(PangoLayout *layout)
static void error(char *msg)
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
static __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
static void blur_2D_Bspline(const float *const restrict in, float *const restrict out, const size_t width, const size_t height)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const dt_colormatrix_t XYZ_D65_to_D50_CAT16
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
static float dt_camera_rgb_luminance(const float4 rgb)
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
dt_iop_order_iccprofile_info_t * dt_colorspaces_add_profile(const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
Find-or-build the derived matrix/LUT data for a profile identity, memoised.
void dt_ioppr_free_iccprofile_params_cl(dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
free parameters build with the previous function.
cl_int dt_ioppr_build_iccprofile_params_cl(const dt_iop_order_iccprofile_info_t *const profile_info, const int devid, dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
build the required parameters for a kernel that uses a profile info.
const float *const const float coeff[3]
static float4 LMS_to_XYZ(const float4 LMS)
static float4 Yrg_to_LMS(const float4 Yrg)
static float4 LMS_to_Yrg(const float4 LMS)
static float4 XYZ_to_LMS(const float4 XYZ)
void dt_colorprofiles_get_settings(dt_colorprofiles_settings_t *const out)
Copy the current settings into caller-provided storage, under one lock.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static dt_aligned_pixel_t rgb
static const float const float const float min
static dt_aligned_pixel_t XYZ
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
static const dt_colormatrix_t M
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
float dt_image_get_exposure_bias(const struct dt_image_t *image_storage)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
static float4 dt_noise_generator_simd(const dt_noise_distribution_t distribution, const float4 mu, const float4 param, uint state[4])
static unsigned int splitmix32(const unsigned long seed)
static float xoshiro128plus(uint state[4])
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_main(dev)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
__DT_CLONE_TARGETS__ dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
GtkWidget * geometry
its size, under the preview
static float dt_log_scale_axis(const float x, const float base)
static void set_color(cairo_t *cr, GdkRGBA color)
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
static void dt_draw_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
static void toe_shoulder_callback(GtkWidget *slider, gpointer user_data)
static gboolean area_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static void _filmic_agx_Yrg_to_xyz_D50(const dt_aligned_pixel_t Yrg, dt_aligned_pixel_t xyz_D50)
static gboolean area_scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
const char ** description(struct dt_iop_module_t *self)
static gboolean area_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static gboolean _filmic_agx_build_displaced(const dt_iop_order_iccprofile_info_t *const work_profile, const float inset[3], const float rotation[3], dt_colormatrix_t M)
static __DT_CLONE_TARGETS__ void display_mask(const float *const restrict mask, float *const restrict out, const size_t width, const size_t height)
dt_iop_filmic_noise_distribution_t
@ DT_FILMIC_NOISE_UNIFORM
@ DT_FILMIC_NOISE_POISSONIAN
@ DT_FILMIC_NOISE_GAUSSIAN
dt_iop_filmicrgb_curve_type_t
@ DT_FILMIC_CURVE_RATIONAL
@ DT_FILMIC_CURVE_SIGMOID
void gui_reset(dt_iop_module_t *self)
void filmic_gui_draw_icon(cairo_t *cr, struct dt_iop_filmicrgb_gui_button_data_t *button, struct dt_iop_filmicrgb_gui_data_t *g)
static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
dt_iop_filmic_rgb_gui_mode_t
@ DT_FILMIC_GUI_BASECURVE
@ DT_FILMIC_GUI_BASECURVE_LOG
static const dt_iop_order_iccprofile_info_t * _filmic_get_output_profile(const dt_dev_pixelpipe_t *pipe, const dt_iop_filmicrgb_data_t *const data)
static __DT_CLONE_TARGETS__ void filmic_split_v1(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height)
void reload_defaults(dt_iop_module_t *module)
static __DT_CLONE_TARGETS__ void wavelets_reconstruct_RGB(const float *const restrict HF, const float *const restrict LF, const float *const restrict texture, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height, const size_t ch, const float gamma, const float gamma_comp, const float beta, const float beta_comp, const float delta, const size_t s, const size_t scales)
static void _filmic_agx_xyz_D50_to_Yrg(const dt_aligned_pixel_t xyz_D50, dt_aligned_pixel_t Yrg)
dt_iop_filmicrgb_colorscience_type_t
@ DT_FILMIC_COLORSCIENCE_V1
@ DT_FILMIC_COLORSCIENCE_V2
@ DT_FILMIC_COLORSCIENCE_V7
@ DT_FILMIC_COLORSCIENCE_V9
@ DT_FILMIC_COLORSCIENCE_V5
@ DT_FILMIC_COLORSCIENCE_V4
@ DT_FILMIC_COLORSCIENCE_V6
@ DT_FILMIC_COLORSCIENCE_V3
@ DT_FILMIC_COLORSCIENCE_V10
@ DT_FILMIC_COLORSCIENCE_V8
__DT_CLONE_TARGETS__ int process(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const restrict ivoid, void *const restrict ovoid)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static void dt_cairo_draw_arrow(cairo_t *cr, double origin_x, double origin_y, double destination_x, double destination_y, gboolean show_head)
static void apply_auto_grey(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void filmic_chroma_v2_v3(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version)
static void apply_auto_black(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void wavelets_reconstruct_ratios(const float *const restrict HF, const float *const restrict LF, const float *const restrict texture, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height, const size_t ch, const float gamma, const float gamma_comp, const float beta, const float beta_comp, const float delta, const size_t s, const size_t scales)
static void _mat3_identity(dt_colormatrix_t M)
static void _filmic_update_hl_deprecation(dt_iop_module_t *self)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
static cl_int reconstruct_highlights_cl(const dt_dev_pixelpipe_t *pipe, cl_mem in, cl_mem mask, cl_mem reconstructed, const dt_iop_filmicrgb_reconstruction_type_t variant, dt_iop_filmicrgb_global_data_t *const gd, const dt_iop_filmicrgb_data_t *const data, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_in)
#define CIE_Y_1931_to_CIE_Y_2006(x)
static __DT_CLONE_TARGETS__ void filmic_chroma_v4(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version, const float display_black, const float display_white)
static __DT_CLONE_TARGETS__ void filmic_chroma_v1(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height)
static __DT_CLONE_TARGETS__ void filmic_split_v4(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version, const float display_black, const float display_white)
void gui_init(dt_iop_module_t *self)
dt_iop_filmicrgb_methods_type_t
@ DT_FILMIC_METHOD_POWER_NORM
@ DT_FILMIC_METHOD_EUCLIDEAN_NORM_V1
@ DT_FILMIC_METHOD_MAX_RGB
@ DT_FILMIC_METHOD_EUCLIDEAN_NORM_V2
@ DT_FILMIC_METHOD_LUMINANCE
static __DT_CLONE_TARGETS__ void filmic_split_v2_v3(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height)
static float log_tonemapping(const float x, const float grey, const float black, const float dynamic_range)
dt_iop_filmicrgb_reconstruction_type_t
@ DT_FILMIC_RECONSTRUCT_RATIOS
@ DT_FILMIC_RECONSTRUCT_RGB
static void filmic_v3_legacy_to_direct(const dt_iop_filmicrgb_params_t *const p, float *const toe, float *const shoulder)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
dt_iop_filmicrgb_gui_button_t
@ DT_FILMIC_GUI_BUTTON_LAST
@ DT_FILMIC_GUI_BUTTON_LABELS
@ DT_FILMIC_GUI_BUTTON_TYPE
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
static __DT_CLONE_TARGETS__ int get_scales(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *roi_in, const dt_dev_pixelpipe_iop_t *const piece)
static int reconstruct_highlights(const dt_dev_pixelpipe_t *const pipe, const float *const restrict in, const float *const restrict mask, float *const restrict reconstructed, const dt_iop_filmicrgb_reconstruction_type_t variant, const size_t ch, const dt_iop_filmicrgb_data_t *const data, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
void commit_params(dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void apply_auto_white_point_source(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static float exp_tonemapping_v2(const float x, const float grey, const float black, const float dynamic_range)
void cleanup_global(dt_iop_module_so_t *module)
static void filmic_prepare_simd_matrices(const dt_colormatrix_t input_matrix, const dt_colormatrix_t output_matrix, const dt_colormatrix_t export_input_matrix, const dt_colormatrix_t export_output_matrix, dt_iop_filmicrgb_simd_matrices_t *const simd_matrices)
static gboolean area_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static __DT_CLONE_TARGETS__ gint mask_clipped_pixels(const float *const restrict in, float *const restrict mask, const float normalize, const float feathering, const size_t width, const size_t height, const size_t ch)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
static gboolean area_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static void inpaint_noise(const float *const in, const float *const mask, float *const inpainted, const float noise_level, const float threshold, const dt_noise_distribution_t noise_distribution, const size_t width, const size_t height)
static void apply_autotune(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void filmic_agx(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height, const size_t ch, const float display_black, const float display_white)
static __DT_CLONE_TARGETS__ void filmic_v5(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height, const size_t ch, const float display_black, const float display_white)
static gboolean filmic_v3_compute_geometry(const dt_iop_filmicrgb_params_t *const p, dt_iop_filmicrgb_v3_geometry_t *const geometry)
static void show_mask_callback(GtkToggleButton *button, GdkEventButton *event, gpointer user_data)
static __DT_CLONE_TARGETS__ void wavelets_detail_level(const float *const restrict detail, const float *const restrict LF, float *const restrict HF, float *const restrict texture, const size_t width, const size_t height, const size_t ch)
static void convert_to_spline_v3(dt_iop_filmicrgb_params_t *n)
static __DT_CLONE_TARGETS__ void compute_ratios(const float *const restrict in, float *const restrict norms, float *const restrict ratios, const dt_iop_order_iccprofile_info_t *const work_profile, const int variant, const size_t width, const size_t height)
static void filmic_v3_direct_to_legacy(const dt_iop_filmicrgb_params_t *const p, const float toe, const float shoulder, float *const latitude, float *const balance)
dt_iop_filmicrgb_spline_version_type_t
@ DT_FILMIC_SPLINE_VERSION_V2
@ DT_FILMIC_SPLINE_VERSION_V3
@ DT_FILMIC_SPLINE_VERSION_V1
static float filmic_sigmoid_scale(const float limit_x, const float limit_y, const float transition_x, const float transition_y, const float slope, const float power)
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void filmic_gui_sync_toe_shoulder(dt_iop_module_t *self)
void init_global(dt_iop_module_so_t *module)
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
static void filmic_agx_prepare_bracket(const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_colorscience_type_t variant, dt_colormatrix_t inset, dt_colormatrix_t outset)
static gboolean filmic_v3_compute_nodes_from_legacy(const dt_iop_filmicrgb_params_t *const p, dt_iop_filmicrgb_v3_geometry_t *const geometry, dt_iop_filmicrgb_v3_nodes_t *const nodes)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
static gboolean _filmic_is_agx(const dt_iop_filmicrgb_colorscience_type_t v)
static __DT_CLONE_TARGETS__ void init_reconstruct(const float *const restrict in, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static float linear_saturation(const float x, const float luminance, const float saturation)
static gboolean dt_iop_filmic_rgb_compute_spline(const dt_iop_filmicrgb_params_t *const p, struct dt_iop_filmic_rgb_spline_t *const spline)
#define FILMIC_RECONSTRUCT_DEPRECATED
static __DT_CLONE_TARGETS__ void restore_ratios(float *const restrict ratios, const float *const restrict norms, const size_t width, const size_t height)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
gboolean runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static int gauss_solve(double *A, double *b, int n)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
GtkWidget * dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, const gchar *label, const gchar *ctrl_label, GCallback callback, gboolean local, guint accel_key, GdkModifierType mods, DTGTKCairoPaintIconFunc paint, GtkWidget *box)
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_ui_section_label_new(const gchar *str)
GtkWidget * dt_ui_label_new(const gchar *str)
_lib_location_type_t type
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict luminance
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define CLAMPF(a, mn, mx)
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
static void transpose_3xSSE(const dt_colormatrix_t input, dt_colormatrix_t output)
static void pack_3xSSE_to_3x4(const dt_colormatrix_t input, float output[12])
static void dt_colormatrix_mul(dt_colormatrix_t dst, const dt_colormatrix_t m1, const dt_colormatrix_t m2)
static int mat3SSEinv(dt_colormatrix_t dst, const dt_colormatrix_t src)
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
void dt_ui_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and report every "switch_page" to the hos...
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
#define __OMP_SIMD__(...)
#define dt_omploop_sfence()
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static float fmaxabsf(const float a, const float b)
static float clamp_simd(const float x)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
dt_colorspaces_color_mode_t
What the output transform is being asked to show: the picture, or a proof of it.
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_each_channel(_var,...)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
const float const int flip
Consistent snapshot of the display and soft-proofing settings.
char softproof_filename[DT_IOP_COLOR_ICC_LEN]
only meaningful for DT_COLORSPACE_FILE
dt_colorspaces_color_profile_type_t softproof_type
proofing target identity
dt_iop_color_intent_t softproof_intent
rendering intent to the proofing target
dt_colorspaces_color_mode_t mode
NORMAL / SOFTPROOF / GAMUTCHECK.
The device-side view of a dt_iop_order_iccprofile_info_t: the scalar fields only.
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
dt_iop_buffer_type_t datatype
dt_iop_filmicrgb_curve_type_t type[2]
int high_quality_reconstruction
float reconstruct_feather
char softproof_filename[512]
float reconstruct_structure_vs_texture
float reconstruct_grey_vs_color
dt_noise_distribution_t noise_distribution
dt_colorspaces_color_profile_type_t softproof_type
float reconstruct_bloom_vs_details
dt_iop_color_intent_t softproof_intent
dt_colorspaces_color_mode_t softproof_mode
struct dt_iop_filmic_rgb_spline_t spline DT_ALIGNED_ARRAY
float reconstruct_threshold
int kernel_filmic_rgb_chroma
int kernel_filmic_bspline_vertical
int kernel_filmic_rgb_split
int kernel_filmic_wavelets_reconstruct
int kernel_filmic_wavelets_detail
int kernel_filmic_show_mask
int kernel_filmic_compute_ratios
int kernel_filmic_init_reconstruct
int kernel_filmic_restore_ratios
int kernel_filmic_bspline_vertical_local
int kernel_filmic_bspline_horizontal
int kernel_filmic_inpaint_noise
int kernel_filmic_bspline_horizontal_local
GtkWidget * high_quality_reconstruction
GtkWidget * autoset_display_gamma
GtkWidget * reconstruct_grey_vs_color
GtkWidget * auto_hardness
dt_iop_filmicrgb_gui_button_data_t buttons[DT_FILMIC_GUI_BUTTON_LAST]
GtkWidget * reconstruct_bloom_vs_details
GtkWidget * reconstruct_threshold
GtkWidget * show_highlight_mask
GtkWidget * white_point_target
GtkWidget * grey_point_source
GtkWidget * spline_version
GtkStyleContext * context
GtkWidget * preserve_color
dt_iop_filmicrgb_gui_button_t active_button
GtkWidget * grey_point_target
dt_iop_filmic_rgb_gui_mode_t gui_mode
GtkWidget * black_point_source
GtkWidget * reconstruct_structure_vs_texture
GtkWidget * reconstruct_page
GtkWidget * reconstruct_feather
GtkWidget * noise_distribution
GtkWidget * black_point_target
struct dt_iop_filmic_rgb_spline_t spline DT_ALIGNED_ARRAY
GtkWidget * white_point_source
GtkWidget * security_factor
GtkWidget * compensate_icc_black
float reconstruct_threshold
float reconstruct_grey_vs_color
float reconstruct_feather
dt_iop_filmicrgb_curve_type_t shadows
dt_iop_filmicrgb_spline_version_type_t spline_version
dt_iop_filmicrgb_colorscience_type_t version
dt_iop_filmic_noise_distribution_t noise_distribution
dt_iop_filmicrgb_methods_type_t preserve_color
int high_quality_reconstruction
dt_iop_filmicrgb_curve_type_t highlights
float reconstruct_bloom_vs_details
gboolean compensate_icc_black
float reconstruct_structure_vs_texture
dt_aligned_pixel_simd_t input[3]
dt_aligned_pixel_simd_t output[3]
dt_aligned_pixel_simd_t export_output[3]
dt_aligned_pixel_simd_t export_input[3]
gboolean contrast_clamped
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
dt_iop_global_data_t * global_data
gboolean workflow_enabled
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
int nonlinearlut
Non-zero when the profile has tone curves at all; tested as a boolean everywhere, but it is really th...
int lutsize
Entry count of each of the six LUTs. Always 65536 in practice: both callers of dt_ioppr_init_profile_...
dt_colormatrix_t matrix_out
XYZ (D50) -> RGB, row-major; the inverse of matrix_in.
float * lut_in[3]
Per-channel encoded -> linear tone curve, lutsize entries each, sampled over [0,1]....
dt_colormatrix_t matrix_in_transposed
dt_colormatrix_t matrix_in
RGB -> XYZ (D50), row-major. matrix_in[1][*] is the luminance row. NaN in [0][0] marks the whole prof...
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__