From 6478859b4f190d907b6b0bdc9b41bed4b701dfd0 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak Date: Sun, 1 May 2022 13:57:10 -0400 Subject: [PATCH] tests/color-shaper-matrix: prepare for cLUT type profiles We will want to run the same color spaces with different types of ICC profiles. To help with that: 1. Let struct lcms_pipeline define the test color space and transformations and move the tolerance into a new per test case structure. 2. Added profile type: PTYPE_MATRIX_SHAPER, PTYPE_CLUT. PTYPE_MATRIX_SHAPER is the previously implemented type. Co-authored-by: Pekka Paalanen Signed-off-by: Vitaly Prosyak Signed-off-by: Pekka Paalanen --- tests/color-shaper-matrix-test.c | 194 +++++++++++++++++-------------- 1 file changed, 109 insertions(+), 85 deletions(-) diff --git a/tests/color-shaper-matrix-test.c b/tests/color-shaper-matrix-test.c index 5e6beb3a..46e9ac92 100644 --- a/tests/color-shaper-matrix-test.c +++ b/tests/color-shaper-matrix-test.c @@ -55,10 +55,6 @@ struct lcms_pipeline { * tone curve enum */ enum transfer_fn post_fn; - /** - * 2/255 or 3/255 maximum possible error, where 255 is 8 bit max value - */ - int tolerance; }; static const int WINDOW_WIDTH = 256; @@ -66,9 +62,9 @@ static const int WINDOW_HEIGHT = 24; static cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 }; -struct setup_args { - struct fixture_metadata meta; - struct lcms_pipeline pipeline; +enum profile_type { + PTYPE_MATRIX_SHAPER, + PTYPE_CLUT, }; /* @@ -78,69 +74,77 @@ struct setup_args { * colour.matrix_RGB_to_RGB(colour.RGB_COLOURSPACES['sRGB'], colour.RGB_COLOURSPACES['Adobe RGB (1998)'], None) * colour.matrix_RGB_to_RGB(colour.RGB_COLOURSPACES['sRGB'], colour.RGB_COLOURSPACES['ITU-R BT.2020'], None) */ -const struct setup_args arr_setup[] = { - { - .meta.name = "sRGB->sRGB unity", - .pipeline = { - .color_space = "sRGB", - .prim_output = { - .Red = { 0.640, 0.330, 1.0 }, - .Green = { 0.300, 0.600, 1.0 }, - .Blue = { 0.150, 0.060, 1.0 } - }, - .pre_fn = TRANSFER_FN_SRGB_EOTF, - .mat = LCMSMAT3(1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0), - .post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE, - .tolerance = 0 - } + +const struct lcms_pipeline pipeline_sRGB = { + .color_space = "sRGB", + .prim_output = { + .Red = { 0.640, 0.330, 1.0 }, + .Green = { 0.300, 0.600, 1.0 }, + .Blue = { 0.150, 0.060, 1.0 } }, - { - .meta.name = "sRGB->adobeRGB", - .pipeline = { - .color_space = "adobeRGB", - .prim_output = { - .Red = { 0.640, 0.330, 1.0 }, - .Green = { 0.210, 0.710, 1.0 }, - .Blue = { 0.150, 0.060, 1.0 } - }, - .pre_fn = TRANSFER_FN_SRGB_EOTF, - .mat = LCMSMAT3(0.715119, 0.284881, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.041169, 0.958831), - .post_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE, - .tolerance = 1 - /* - * Tolerance depends more on the 1D LUT used for the - * inv EOTF than the tested 3D LUT size: - * 9x9x9, 17x17x17, 33x33x33, 127x127x127 - */ - } + .pre_fn = TRANSFER_FN_SRGB_EOTF, + .mat = LCMSMAT3(1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0), + .post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE +}; + +const struct lcms_pipeline pipeline_adobeRGB = { + .color_space = "adobeRGB", + .prim_output = { + .Red = { 0.640, 0.330, 1.0 }, + .Green = { 0.210, 0.710, 1.0 }, + .Blue = { 0.150, 0.060, 1.0 } }, - { - .meta.name = "sRGB->bt2020", - .pipeline = { - .color_space = "bt2020", - .prim_output = { - .Red = { 0.708, 0.292, 1.0 }, - .Green = { 0.170, 0.797, 1.0 }, - .Blue = { 0.131, 0.046, 1.0 } - }, - .pre_fn = TRANSFER_FN_SRGB_EOTF, - .mat = LCMSMAT3(0.627402, 0.329292, 0.043306, - 0.069095, 0.919544, 0.011360, - 0.016394, 0.088028, 0.895578), - /* this is equivalent to BT.1886 with zero black level */ - .post_fn = TRANSFER_FN_POWER2_4_EOTF_INVERSE, - .tolerance = 5 - /* - * TODO: when we add power-law in the curve enumeration - * in GL-renderer, then we should fix the tolerance - * as the error should reduce a lot. - */ - } - } + .pre_fn = TRANSFER_FN_SRGB_EOTF, + .mat = LCMSMAT3( 0.715127, 0.284868, 0.000005, + 0.000001, 0.999995, 0.000004, + -0.000003, 0.041155, 0.958848), + .post_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE +}; + +const struct lcms_pipeline pipeline_BT2020 = { + .color_space = "bt2020", + .prim_output = { + .Red = { 0.708, 0.292, 1.0 }, + .Green = { 0.170, 0.797, 1.0 }, + .Blue = { 0.131, 0.046, 1.0 } + }, + .pre_fn = TRANSFER_FN_SRGB_EOTF, + .mat = LCMSMAT3(0.627402, 0.329292, 0.043306, + 0.069095, 0.919544, 0.011360, + 0.016394, 0.088028, 0.895578), + /* this is equivalent to BT.1886 with zero black level */ + .post_fn = TRANSFER_FN_POWER2_4_EOTF_INVERSE, +}; + +struct setup_args { + struct fixture_metadata meta; + const struct lcms_pipeline *pipeline; + /** + * 2/255 or 3/255 maximum possible error, where 255 is 8 bit max value + * + * Tolerance depends more on the 1D LUT used for the + * inv EOTF than the tested 3D LUT size: + * 9x9x9, 17x17x17, 33x33x33, 127x127x127 + * + * TODO: when we add power-law in the curve enumeration + * in GL-renderer, then we should fix the tolerance + * as the error should reduce a lot. + */ + int tolerance; + /** + * 3DLUT dimension size + */ + int dim_size; + enum profile_type type; +}; + +static const struct setup_args my_setup_args[] = { + /* name, pipeline, tolerance, dim, profile type */ + { { "sRGB->sRGB" }, &pipeline_sRGB, 0, 0, PTYPE_MATRIX_SHAPER }, + { { "sRGB->adobeRGB" }, &pipeline_adobeRGB, 1, 0, PTYPE_MATRIX_SHAPER }, + { { "sRGB->BT2020" }, &pipeline_BT2020, 5, 0, PTYPE_MATRIX_SHAPER }, }; struct image_header { @@ -219,7 +223,8 @@ gen_ramp_rgb(const struct image_header *header, int bitwidth, int width_bar) } static cmsHPROFILE -build_lcms_profile_output(const struct lcms_pipeline *pipeline) +build_lcms_matrix_shaper_profile_output(cmsContext context_id, + const struct lcms_pipeline *pipeline) { cmsToneCurve *arr_curves[3]; cmsHPROFILE hRGB; @@ -240,12 +245,12 @@ build_lcms_profile_output(const struct lcms_pipeline *pipeline) */ arr_curves[0] = arr_curves[1] = arr_curves[2] = - cmsBuildParametricToneCurve(NULL, + cmsBuildParametricToneCurve(context_id, (-1) * type_inverse_tone_curve, inverse_tone_curve_param); assert(arr_curves[0]); - hRGB = cmsCreateRGBProfileTHR(NULL, &wp_d65, + hRGB = cmsCreateRGBProfileTHR(context_id, &wp_d65, &pipeline->prim_output, arr_curves); assert(hRGB); @@ -253,8 +258,22 @@ build_lcms_profile_output(const struct lcms_pipeline *pipeline) return hRGB; } +static cmsHPROFILE +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); + case PTYPE_CLUT: + return NULL; + } + + return NULL; +} + static char * -build_output_icc_profile(const struct lcms_pipeline *pipe) +build_output_icc_profile(const struct setup_args *arg) { char *profile_name = NULL; cmsHPROFILE profile = NULL; @@ -264,11 +283,15 @@ build_output_icc_profile(const struct lcms_pipeline *pipe) wd = realpath(".", NULL); assert(wd); - ret = asprintf(&profile_name, "%s/matrix-shaper-test-%s.icm", wd, - pipe->color_space); + if (arg->type == PTYPE_MATRIX_SHAPER) + ret = asprintf(&profile_name, "%s/matrix-shaper-test-%s.icm", wd, + arg->pipeline->color_space); + else + ret = asprintf(&profile_name, "%s/cLUT-test-%s.icm", wd, + arg->pipeline->color_space); assert(ret > 0); - profile = build_lcms_profile_output(pipe); + profile = build_lcms_profile_output(NULL, arg); assert(profile); saved = cmsSaveProfileToFile(profile, profile_name); @@ -293,7 +316,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg) setup.height = WINDOW_HEIGHT; setup.shell = SHELL_TEST_DESKTOP; - file_name = build_output_icc_profile(&arg->pipeline); + file_name = build_output_icc_profile(arg); if (!file_name) return RESULT_HARD_ERROR; @@ -308,7 +331,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg) return weston_test_harness_execute_as_client(harness, &setup); } -DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, arr_setup, meta); +DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta); static bool compare_float(float ref, float dst, int x, const char *chan, @@ -362,7 +385,7 @@ process_pipeline_comparison(const struct image_header *src, const char *const chan_name[COLOR_CHAN_NUM] = { "r", "g", "b" }; const float max_pixel_value = 255.0; struct color_float max_diff_pipeline = { .rgb = { 0.0f, 0.0f, 0.0f } }; - float max_allow_diff = arg->pipeline.tolerance / max_pixel_value; + float max_allow_diff = arg->tolerance / max_pixel_value; float max_err = 0.0f; bool ok = true; uint32_t *row_ptr, *row_ptr_shot; @@ -380,9 +403,9 @@ process_pipeline_comparison(const struct image_header *src, pix_src = a8r8g8b8_to_float(row_ptr[x]); pix_shot = a8r8g8b8_to_float(row_ptr_shot[x]); /* do pipeline processing */ - process_pixel_using_pipeline(arg->pipeline.pre_fn, - &arg->pipeline.mat, - arg->pipeline.post_fn, + process_pixel_using_pipeline(arg->pipeline->pre_fn, + &arg->pipeline->mat, + arg->pipeline->post_fn, &pix_src, &pix_src_pipeline); /* check if pipeline matches to shader variant */ @@ -399,11 +422,12 @@ process_pipeline_comparison(const struct image_header *src, for (chan = 0; chan < COLOR_CHAN_NUM; chan++) max_err = MAX(max_err, max_diff_pipeline.rgb[chan]); - testlog("%s %s %s tol_req %d, tol_cal %f, max diff: r=%f, g=%f, b=%f\n", + testlog("%s %s %s tol_req %d, tol_cal %f, max diff: r=%f, g=%f, b=%f %s\n", __func__, ok == true? "SUCCESS":"FAILURE", - arg->meta.name, arg->pipeline.tolerance, + arg->meta.name, arg->tolerance, max_err * max_pixel_value, - max_diff_pipeline.r, max_diff_pipeline.g, max_diff_pipeline.b); + max_diff_pipeline.r, max_diff_pipeline.g, max_diff_pipeline.b, + arg->type == PTYPE_MATRIX_SHAPER ? "matrix-shaper" : "cLUT"); return ok; } @@ -462,7 +486,7 @@ TEST(shaper_matrix) assert(shot); match = verify_image(shot, "shaper_matrix", seq_no, NULL, seq_no); - assert(check_process_pattern_ex(buf, shot, &arr_setup[seq_no])); + assert(check_process_pattern_ex(buf, shot, &my_setup_args[seq_no])); assert(match); buffer_destroy(shot); buffer_destroy(buf);