From 8c9dd4febbe129a29d045974a89eec8e28bd3418 Mon Sep 17 00:00:00 2001 From: Leandro Ribeiro Date: Fri, 21 Apr 2023 15:27:30 -0300 Subject: [PATCH] tests/color-icc-output: add ICC VCGT tests There are some ICC profiles that contain something named VCGT tag. These are usually power curves (y = x ^ exp) that were loaded in the video card when the ICC profile was created. So the compositor should mimic that in order to use the profile. Weston already has support for that, but our ICC profile tests were missing this case. This adds such tests. For testing purposes, we have added tests with different exponents per color channel. Signed-off-by: Leandro Ribeiro --- tests/color-icc-output-test.c | 61 ++++++++++++++---- tests/color_util.c | 22 ++++++- tests/color_util.h | 4 ++ tests/reference/output-icc-decorations-03.png | Bin 0 -> 689 bytes tests/reference/output-icc-decorations-04.png | Bin 0 -> 689 bytes tests/reference/output_icc_alpha_blend-03.png | Bin 0 -> 394 bytes tests/reference/output_icc_alpha_blend-04.png | Bin 0 -> 390 bytes tests/reference/shaper_matrix-03.png | Bin 0 -> 433 bytes tests/reference/shaper_matrix-04.png | Bin 0 -> 530 bytes 9 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 tests/reference/output-icc-decorations-03.png create mode 100644 tests/reference/output-icc-decorations-04.png create mode 100644 tests/reference/output_icc_alpha_blend-03.png create mode 100644 tests/reference/output_icc_alpha_blend-04.png create mode 100644 tests/reference/shaper_matrix-03.png create mode 100644 tests/reference/shaper_matrix-04.png diff --git a/tests/color-icc-output-test.c b/tests/color-icc-output-test.c index 62103c4b..076a360d 100644 --- a/tests/color-icc-output-test.c +++ b/tests/color-icc-output-test.c @@ -161,15 +161,25 @@ struct setup_args { /** Two-norm error limit for cLUT DToB->BToD roundtrip */ float clut_roundtrip_tolerance; + + /** + * VCGT tag exponents for each channel. If any is zeroed, we ignore + * the VCGT tag. + */ + double vcgt_exponents[COLOR_CHAN_NUM]; }; static const struct setup_args my_setup_args[] = { - /* name, ref img, pipeline, tolerance, dim, profile type, clut tolerance */ - { { "sRGB->sRGB MAT" }, 0, &pipeline_sRGB, 0.0, 0, PTYPE_MATRIX_SHAPER }, - { { "sRGB->adobeRGB MAT" }, 1, &pipeline_adobeRGB, 1.4, 0, PTYPE_MATRIX_SHAPER }, - { { "sRGB->BT2020 MAT" }, 2, &pipeline_BT2020, 4.5, 0, PTYPE_MATRIX_SHAPER }, - { { "sRGB->sRGB CLUT" }, 0, &pipeline_sRGB, 0.0, 17, PTYPE_CLUT, 0.0005 }, - { { "sRGB->adobeRGB CLUT" }, 1, &pipeline_adobeRGB, 1.8, 17, PTYPE_CLUT, 0.0065 }, + /* name, ref img, pipeline, tolerance, dim, profile type, clut tolerance, vcgt_exponents */ + { { "sRGB->sRGB MAT" }, 0, &pipeline_sRGB, 0.0, 0, PTYPE_MATRIX_SHAPER }, + { { "sRGB->sRGB MAT VCGT" }, 3, &pipeline_sRGB, 0.8, 0, PTYPE_MATRIX_SHAPER, 0.0000, {1.1, 1.2, 1.3} }, + { { "sRGB->adobeRGB MAT" }, 1, &pipeline_adobeRGB, 1.4, 0, PTYPE_MATRIX_SHAPER }, + { { "sRGB->adobeRGB MAT VCGT" }, 4, &pipeline_adobeRGB, 1.0, 0, PTYPE_MATRIX_SHAPER, 0.0000, {1.1, 1.2, 1.3} }, + { { "sRGB->BT2020 MAT" }, 2, &pipeline_BT2020, 4.5, 0, PTYPE_MATRIX_SHAPER }, + { { "sRGB->sRGB CLUT" }, 0, &pipeline_sRGB, 0.0, 17, PTYPE_CLUT, 0.0005 }, + { { "sRGB->sRGB CLUT VCGT" }, 3, &pipeline_sRGB, 0.9, 17, PTYPE_CLUT, 0.0005, {1.1, 1.2, 1.3} }, + { { "sRGB->adobeRGB CLUT" }, 1, &pipeline_adobeRGB, 1.8, 17, PTYPE_CLUT, 0.0065 }, + { { "sRGB->adobeRGB CLUT VCGT" }, 4, &pipeline_adobeRGB, 1.1, 17, PTYPE_CLUT, 0.0065, {1.1, 1.2, 1.3} }, }; static void @@ -247,6 +257,24 @@ create_cLUT_from_matrix(cmsContext context_id, const struct lcmsMAT3 *mat, int d return cLUT_stage; } +static void +vcgt_tag_add_to_profile(cmsContext context_id, cmsHPROFILE profile, + const double vcgt_exponents[COLOR_CHAN_NUM]) +{ + cmsToneCurve *vcgt_tag_curves[COLOR_CHAN_NUM]; + unsigned int i; + + if (!should_include_vcgt(vcgt_exponents)) + return; + + for (i = 0; i < COLOR_CHAN_NUM; i++) + vcgt_tag_curves[i] = cmsBuildGamma(context_id, vcgt_exponents[i]); + + assert(cmsWriteTag(profile, cmsSigVcgtTag, vcgt_tag_curves)); + + cmsFreeToneCurveTriple(vcgt_tag_curves); +} + /* * Originally the cLUT profile test attempted to use the AToB/BToA tags. Those * come with serious limitations though: at most uint16 representation for @@ -332,6 +360,8 @@ build_lcms_clut_profile_output(cmsContext context_id, cmsLinkTag(hRGB, cmsSigDToB2Tag, cmsSigDToB0Tag); cmsLinkTag(hRGB, cmsSigDToB3Tag, cmsSigDToB0Tag); + vcgt_tag_add_to_profile(context_id, hRGB, arg->vcgt_exponents); + roundtrip_verification(DToB0, BToD0, arg->clut_roundtrip_tolerance); cmsPipelineFree(BToD0); @@ -344,14 +374,14 @@ build_lcms_clut_profile_output(cmsContext context_id, static cmsHPROFILE build_lcms_matrix_shaper_profile_output(cmsContext context_id, - const struct lcms_pipeline *pipeline) + const struct setup_args *arg) { cmsToneCurve *arr_curves[3]; cmsHPROFILE hRGB; int type_inverse_tone_curve; double inverse_tone_curve_param[5]; - assert(find_tone_curve_type(pipeline->post_fn, &type_inverse_tone_curve, + assert(find_tone_curve_type(arg->pipeline->post_fn, &type_inverse_tone_curve, inverse_tone_curve_param)); /* @@ -371,9 +401,11 @@ build_lcms_matrix_shaper_profile_output(cmsContext context_id, assert(arr_curves[0]); hRGB = cmsCreateRGBProfileTHR(context_id, &wp_d65, - &pipeline->prim_output, arr_curves); + &arg->pipeline->prim_output, arr_curves); assert(hRGB); + vcgt_tag_add_to_profile(context_id, hRGB, arg->vcgt_exponents); + cmsFreeToneCurve(arr_curves[0]); return hRGB; } @@ -383,8 +415,7 @@ build_lcms_profile_output(cmsContext context_id, const struct setup_args *arg) { switch (arg->type) { case PTYPE_MATRIX_SHAPER: - return build_lcms_matrix_shaper_profile_output(context_id, - arg->pipeline); + return build_lcms_matrix_shaper_profile_output(context_id, arg); case PTYPE_CLUT: return build_lcms_clut_profile_output(context_id, arg); } @@ -561,6 +592,7 @@ process_pipeline_comparison(const struct buffer *src_buf, process_pixel_using_pipeline(arg->pipeline->pre_fn, &arg->pipeline->mat, arg->pipeline->post_fn, + arg->vcgt_exponents, &pix_src, &pix_src_pipeline); rgb_diff_stat_update(&diffstat, @@ -646,6 +678,7 @@ convert_to_blending_space(const struct lcms_pipeline *pip, static void compare_blend(const struct lcms_pipeline *pip, + const double vcgt_exponents[COLOR_CHAN_NUM], struct color_float bg, struct color_float fg, const struct color_float *shot, @@ -668,6 +701,10 @@ compare_blend(const struct lcms_pipeline *pip, /* non-linear encoding for output */ ref = color_float_apply_curve(pip->post_fn, ref); + if (should_include_vcgt(vcgt_exponents)) + for (i = 0; i < COLOR_CHAN_NUM; i++) + ref.rgb[i] = pow(ref.rgb[i], vcgt_exponents[i]); + rgb_diff_stat_update(diffstat, &ref, shot, &fg); } @@ -714,7 +751,7 @@ check_blend_pattern(struct buffer *bg_buf, struct color_float fg = a8r8g8b8_to_float(fg_row[x]); struct color_float shot = a8r8g8b8_to_float(shot_row[x]); - compare_blend(arg->pipeline, bg, fg, &shot, &diffstat); + compare_blend(arg->pipeline, arg->vcgt_exponents, bg, fg, &shot, &diffstat); } rgb_diff_stat_print(&diffstat, "Blending", 8); diff --git a/tests/color_util.c b/tests/color_util.c index fc406d87..5db692e5 100644 --- a/tests/color_util.c +++ b/tests/color_util.c @@ -321,18 +321,38 @@ color_float_apply_matrix(const struct lcmsMAT3 *mat, struct color_float c) return result; } +bool +should_include_vcgt(const double vcgt_exponents[COLOR_CHAN_NUM]) +{ + unsigned int i; + + for (i = 0; i < COLOR_CHAN_NUM; i++) + if (vcgt_exponents[i] == 0.0) + return false; + + return true; +} + void process_pixel_using_pipeline(enum transfer_fn pre_curve, const struct lcmsMAT3 *mat, enum transfer_fn post_curve, + const double vcgt_exponents[COLOR_CHAN_NUM], const struct color_float *in, struct color_float *out) { struct color_float cf; + unsigned i; cf = color_float_apply_curve(pre_curve, *in); cf = color_float_apply_matrix(mat, cf); - *out = color_float_apply_curve(post_curve, cf); + cf = color_float_apply_curve(post_curve, cf); + + if (should_include_vcgt(vcgt_exponents)) + for (i = 0; i < COLOR_CHAN_NUM; i++) + cf.rgb[i] = pow(cf.rgb[i], vcgt_exponents[i]); + + *out = cf; } static void diff --git a/tests/color_util.h b/tests/color_util.h index a5003fa8..46817dfc 100644 --- a/tests/color_util.h +++ b/tests/color_util.h @@ -101,10 +101,14 @@ find_tone_curve_type(enum transfer_fn fn, int *type, double params[5]); float apply_tone_curve(enum transfer_fn fn, float r); +bool +should_include_vcgt(const double vcgt_exponents[COLOR_CHAN_NUM]); + void process_pixel_using_pipeline(enum transfer_fn pre_curve, const struct lcmsMAT3 *mat, enum transfer_fn post_curve, + const double vcgt_exponents[COLOR_CHAN_NUM], const struct color_float *in, struct color_float *out); diff --git a/tests/reference/output-icc-decorations-03.png b/tests/reference/output-icc-decorations-03.png new file mode 100644 index 0000000000000000000000000000000000000000..f10f000fa7ca17867cb97592d0679d7f7b0ce947 GIT binary patch literal 689 zcmeAS@N?(olHy`uVBq!ia0y~yVDtg9D>;~e#yFeTcfsqdio>#lIztampAKV-`_d4ign8My=B&4yPiz6UV2#K?6a#^v?saq zJ$dbQ&zzz4+t16#gTe~DWM4f-Mlj5 literal 0 HcmV?d00001 diff --git a/tests/reference/output-icc-decorations-04.png b/tests/reference/output-icc-decorations-04.png new file mode 100644 index 0000000000000000000000000000000000000000..6b0c62224065e479b9c8912236af2eebb981cade GIT binary patch literal 689 zcmeAS@N?(olHy`uVBq!ia0y~yVDtg9D>;~eT=Hc;g8tZRAOr-z3fH_dfWYOm{BRPpJ{&mGHhbMt)cijJ3Z_&pJrb3)N# z;^7HmV$*?$ZKp-7Qv1X?e!Fri<%KPIUjE*`{%)06yDn5#_RXw!ue09UOln@Y!KJ?8sZM;g5V1E`Y&(ZKAG<1X;W8Gdq~>$ zB+z}%1xoD?T=))l$}|aEvZxoq9ZtMN9@qWY`G3lnKdgV|2{!1oT;=xaDZo$+f9|gS zz3a`y_iyE%po`a943dso#v*7o`P&s+&weKpHWdS|&~Yl-#Uxo_u&=WnatU+4cj g4o@@#r5YyvU{38!OR?4n?gpv!boFyt=akR{0ES5 literal 0 HcmV?d00001 diff --git a/tests/reference/output_icc_alpha_blend-03.png b/tests/reference/output_icc_alpha_blend-03.png new file mode 100644 index 0000000000000000000000000000000000000000..9072beda2dfc48195d82d2aa4c3502549c5aba51 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BsiFW1ekd=8#bmhh%je~aw!UNO-$g>ukPCxx%`T@(7_2DK`Jha3P7%k zLH_PFwPkCV8kctb6!kjIk*5C4V}G$%EgVloqYzIPEX8!Q^r2hi&uu zgY~L){a>w@`u$D+*wgLjqBq{XY1a8Ky|~8pblTfU?eC{sbLL)ed$T>ZpR?2Q)y-q) zr&_*tcvgAlw4l2-muA|x$BHtQ>&`zh{^?=E_fNIXwXUxA@S0T>-Z}Om6#wK7fMS)78&qol`;+0IFD_+5i9m literal 0 HcmV?d00001 diff --git a/tests/reference/output_icc_alpha_blend-04.png b/tests/reference/output_icc_alpha_blend-04.png new file mode 100644 index 0000000000000000000000000000000000000000..0919087a5f531101b28c84568aacfff2282d245d GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BsiFWXWmfj%BvujlsKJIQ*j(o~Ltv%3Xf%wdtSgbUWsdgz~44 zqC(!pW%8eqKb!e;_W}pTF3Vy)m8|{sd^~S54g2F>MSZn=vZ?pyyjm@;p3h;$+%22T zzfD(MGcC0Lk5Nm<)}w+v9|igz2<~8ifADtWe(9e-zw&Ngb!)eL!Z$y@hN;gOA~Gqb ZzA^A{81Q_~arp!aW=~f?mvv4FO#rm2q{09I literal 0 HcmV?d00001 diff --git a/tests/reference/shaper_matrix-03.png b/tests/reference/shaper_matrix-03.png new file mode 100644 index 0000000000000000000000000000000000000000..693385c8675015243ffc1b762ed51d513685e700 GIT binary patch literal 433 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BsiFW<(U& z_e=l%U^=t=k8ur?N2Uye=GlAN7t)_dnJ8UfAh?sQ*MV1R;%mQip5=?!o~mA&zLV|g z-xZF}y*+^Zx%xBDUJN`p{mird6)b!eFRSSDP8nqPb)a(6S^-bS{) zO>DNC+3q@&&ogMhyguG`njxgN@xNAl9iKi*A=+a%Jnhv#03I&7B@= za(M4`R@PQ>eQp12d8PmO?tu8~QUhxAZzHdce1otoe zw{!=aZddjNr8SP5A4!!2#WeeMS)Wx|;~2bHRa1|}Q{HiX%%i}&2jbxB<5kyGulQTF z{#x}rz~14yW@e+e@s$O}CDU1V`FTp}Zk)GJU{1hue^Ya*sTPZ_I(?t)H#f~x%I@Kj zcS6ch?ibg~nO^!^$24QzM<8B#eL;TjF2nyk_KZH)D}eaQ|I1~Jwt0;#x)XM=KJqT) zR{8USH(Fua1V8!h6Z=HZmMzv2TstjHR(n>N_v*UV);^K#4n^E4R>z^C^-NklgYUd3 S+r~OjlzY1RxvX