From a0584e64cf6701ec6658c5ae4c6d27a47fe14b9f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 17 Jun 2022 15:12:05 +0300 Subject: [PATCH] tests/alpha-blending: replace compare_float() with rgb_diff_stat compare_float() was an ad hoc max error logger with optional debug logging. Now that we have rgb_diff_stat, we can get the same statistics and more with less code. It looks like we would lose the pixel index x, but that can be recovered from the dump file line number. This patch takes care to keep the test condition exactly the same as it was before. The statistics print-out has more details now. The recorded dump position is the foreground color as that varies while the background color is constant. An example Octave function is included to show how to visualize the rgb_diff_stat dump. Signed-off-by: Pekka Paalanen --- tests/alpha-blending-test.c | 115 +++++++----------- .../visualization/weston_plot_rgb_diff_stat.m | 77 ++++++++++++ 2 files changed, 120 insertions(+), 72 deletions(-) create mode 100644 tests/visualization/weston_plot_rgb_diff_stat.m diff --git a/tests/alpha-blending-test.c b/tests/alpha-blending-test.c index 2ec2b255..f5553b17 100644 --- a/tests/alpha-blending-test.c +++ b/tests/alpha-blending-test.c @@ -27,6 +27,7 @@ #include "config.h" #include +#include #include "weston-test-client-helper.h" #include "weston-test-fixture-compositor.h" @@ -119,76 +120,20 @@ fill_alpha_pattern(struct buffer *buf) } } -static bool -compare_float(float ref, float dst, int x, const char *chan, float *max_diff) -{ -#if 0 - /* - * This file can be loaded in Octave for visualization. - * - * S = load('compare_float_dump.txt'); - * - * rvec = S(S(:,1)==114, 2:3); - * gvec = S(S(:,1)==103, 2:3); - * bvec = S(S(:,1)==98, 2:3); - * - * figure - * subplot(3, 1, 1); - * plot(rvec(:,1), rvec(:,2) .* 255, 'r'); - * subplot(3, 1, 2); - * plot(gvec(:,1), gvec(:,2) .* 255, 'g'); - * subplot(3, 1, 3); - * plot(bvec(:,1), bvec(:,2) .* 255, 'b'); - */ - static FILE *fp = NULL; - - if (!fp) - fp = fopen("compare_float_dump.txt", "w"); - fprintf(fp, "%d %d %f\n", chan[0], x, dst - ref); - fflush(fp); -#endif - - float diff = fabsf(ref - dst); - - if (diff > *max_diff) - *max_diff = diff; - - /* - * Allow for +/- 1.5 code points of error in non-linear 8-bit channel - * value. This is necessary for the BLEND_LINEAR case. - * - * With llvmpipe, we could go as low as +/- 0.65 code points of error - * and still pass. - * - * AMD Polaris 11 would be ok with +/- 1.0 code points error threshold - * if not for one particular case of blending (a=254, r=0) into r=255, - * which results in error of 1.29 code points. - */ - if (diff < 1.5f / 255.f) - return true; - - testlog("x=%d %s: ref %f != dst %f, delta %f\n", - x, chan, ref, dst, dst - ref); - - return false; -} - enum blend_space { BLEND_NONLINEAR, BLEND_LINEAR, }; -static bool -verify_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32, - int x, struct color_float *max_diff, - enum blend_space space) +static void +compare_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32, + struct rgb_diff_stat *diffstat, + enum blend_space space) { - const char *const chan_name[COLOR_CHAN_NUM] = { "r", "g", "b" }; struct color_float bg = a8r8g8b8_to_float(bg32); struct color_float fg = a8r8g8b8_to_float(fg32); struct color_float dst = a8r8g8b8_to_float(dst32); struct color_float ref; - bool ok = true; int i; bg = color_float_unpremult(bg); @@ -206,12 +151,7 @@ verify_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32, if (space == BLEND_LINEAR) sRGB_delinearize(&ref); - for (i = 0; i < COLOR_CHAN_NUM; i++) { - ok = compare_float(ref.rgb[i], dst.rgb[i], x, - chan_name[i], &max_diff->rgb[i]) && ok; - } - - return ok; + rgb_diff_stat_update(diffstat, &ref, &dst, &fg); } static uint8_t @@ -259,25 +199,56 @@ static bool check_blend_pattern(struct buffer *bg, struct buffer *fg, struct buffer *shot, enum blend_space space) { + FILE *dump = NULL; +#if 0 + /* + * This file can be loaded in Octave for visualization. Find the script + * in tests/visualization/weston_plot_rgb_diff_stat.m and call it with + * + * weston_plot_rgb_diff_stat('alpha_blend-f01-dump.txt', 255, 8) + */ + dump = fopen_dump_file("dump"); +#endif + + /* + * Allow for +/- 1.5 code points of error in non-linear 8-bit channel + * value. This is necessary for the BLEND_LINEAR case. + * + * With llvmpipe, we could go as low as +/- 0.65 code points of error + * and still pass. + * + * AMD Polaris 11 would be ok with +/- 1.0 code points error threshold + * if not for one particular case of blending (a=254, r=0) into r=255, + * which results in error of 1.29 code points. + */ + const float tolerance = 1.5f / 255.f; + uint32_t *bg_row = get_middle_row(bg); uint32_t *fg_row = get_middle_row(fg); uint32_t *shot_row = get_middle_row(shot); - struct color_float max_diff = { .rgb = { 0.0f, 0.0f, 0.0f } }; + struct rgb_diff_stat diffstat = { .dump = dump, }; bool ret = true; int x; + unsigned i; for (x = 0; x < BLOCK_WIDTH * ALPHA_STEPS - 1; x++) { if (!pixels_monotonic(shot_row, x)) ret = false; - if (!verify_sRGB_blend_a8r8g8b8(bg_row[x], fg_row[x], - shot_row[x], x, &max_diff, - space)) + compare_sRGB_blend_a8r8g8b8(bg_row[x], fg_row[x], shot_row[x], + &diffstat, space); + } + + for (i = 0; i < COLOR_CHAN_NUM; i++) { + if (diffstat.rgb[i].min <= -tolerance || + diffstat.rgb[i].max >= tolerance) ret = false; } - testlog("%s max diff: r=%f, g=%f, b=%f\n", - __func__, max_diff.r, max_diff.g, max_diff.b); + rgb_diff_stat_print(&diffstat, __func__, 8); + + if (dump) + fclose(dump); return ret; } diff --git a/tests/visualization/weston_plot_rgb_diff_stat.m b/tests/visualization/weston_plot_rgb_diff_stat.m new file mode 100644 index 00000000..b2546a31 --- /dev/null +++ b/tests/visualization/weston_plot_rgb_diff_stat.m @@ -0,0 +1,77 @@ +% -- weston_plot_rgb_diff_stat (fname) +% -- weston_plot_rgb_diff_stat (fname, scale) +% -- weston_plot_rgb_diff_stat (fname, scale, x_column) +% Plot an rgb_diff_stat dump file +% +% Creates a new figure and draws four sub-plots: R difference, +% G difference, B difference, and two-norm error. +% +% Scale defaults to 255. It is used to multiply both x and y values +% in all plots. Note that R, G and B plots will contain horizontal lines +% at y = +/- 0.5 to help you see the optimal rounding error range for +% the integer encoding [0, scale]. Two-norm plot contains a horizontal +% line at y = sqrt(0.75) which represents an error sphere with the radius +% equal to the two-norm of RGB error (0.5, 0.5, 0.5). +% +% By default, x-axis is sample index, not multiplied by scale. If +% x_column is given, it is a column index in the dump file to be used as +% the x-axis values, multiplied by scale. Indices start from 1, not 0. + +% SPDX-FileCopyrightText: 2022 Collabora, Ltd. +% SPDX-License-Identifier: MIT + +function weston_plot_rgb_diff_stat(fname, scale, x_column); + +S = load(fname); + +if nargin < 2 + scale = 255; +end +if nargin < 3 + x = 1:size(S, 1); +else + x = S(:, x_column) .* scale; +end + +x_lim = [min(x) max(x)]; + +evec = S(:, 1) .* scale; # two-norm error +rvec = S(:, 2) .* scale; # r diff +gvec = S(:, 3) .* scale; # g diff +bvec = S(:, 4) .* scale; # b diff + +figure + +subplot(4, 1, 1); +plot(x, rvec, 'r'); +plus_minus_half_lines(x_lim); +title(fname, "Interpreter", "none"); +ylabel('R diff'); +axis("tight"); + +subplot(4, 1, 2); +plot(x, gvec, 'g'); +plus_minus_half_lines(x_lim); +ylabel('G diff'); +axis("tight"); + +subplot(4, 1, 3); +plot(x, bvec, 'b'); +plus_minus_half_lines(x_lim); +ylabel('B diff'); +axis("tight"); + +subplot(4, 1, 4); +plot(x, evec, 'k'); +hold on; +plot(x_lim, [1 1] .* sqrt(0.75), 'k:'); +ylabel('Two-norm'); +axis("tight"); + +max_abs_err = [max(abs(rvec)) max(abs(gvec)) max(abs(bvec))] + +function plus_minus_half_lines(x_lim); + +hold on; +plot(x_lim, [0.5 -0.5; 0.5 -0.5], 'k:'); +