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 <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 2 years ago committed by Pekka Paalanen
parent be281478dc
commit a0584e64cf
  1. 115
      tests/alpha-blending-test.c
  2. 77
      tests/visualization/weston_plot_rgb_diff_stat.m

@ -27,6 +27,7 @@
#include "config.h" #include "config.h"
#include <math.h> #include <math.h>
#include <stdio.h>
#include "weston-test-client-helper.h" #include "weston-test-client-helper.h"
#include "weston-test-fixture-compositor.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 { enum blend_space {
BLEND_NONLINEAR, BLEND_NONLINEAR,
BLEND_LINEAR, BLEND_LINEAR,
}; };
static bool static void
verify_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32, compare_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32,
int x, struct color_float *max_diff, struct rgb_diff_stat *diffstat,
enum blend_space space) 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 bg = a8r8g8b8_to_float(bg32);
struct color_float fg = a8r8g8b8_to_float(fg32); struct color_float fg = a8r8g8b8_to_float(fg32);
struct color_float dst = a8r8g8b8_to_float(dst32); struct color_float dst = a8r8g8b8_to_float(dst32);
struct color_float ref; struct color_float ref;
bool ok = true;
int i; int i;
bg = color_float_unpremult(bg); 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) if (space == BLEND_LINEAR)
sRGB_delinearize(&ref); sRGB_delinearize(&ref);
for (i = 0; i < COLOR_CHAN_NUM; i++) { rgb_diff_stat_update(diffstat, &ref, &dst, &fg);
ok = compare_float(ref.rgb[i], dst.rgb[i], x,
chan_name[i], &max_diff->rgb[i]) && ok;
}
return ok;
} }
static uint8_t static uint8_t
@ -259,25 +199,56 @@ static bool
check_blend_pattern(struct buffer *bg, struct buffer *fg, struct buffer *shot, check_blend_pattern(struct buffer *bg, struct buffer *fg, struct buffer *shot,
enum blend_space space) 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 *bg_row = get_middle_row(bg);
uint32_t *fg_row = get_middle_row(fg); uint32_t *fg_row = get_middle_row(fg);
uint32_t *shot_row = get_middle_row(shot); 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; bool ret = true;
int x; int x;
unsigned i;
for (x = 0; x < BLOCK_WIDTH * ALPHA_STEPS - 1; x++) { for (x = 0; x < BLOCK_WIDTH * ALPHA_STEPS - 1; x++) {
if (!pixels_monotonic(shot_row, x)) if (!pixels_monotonic(shot_row, x))
ret = false; ret = false;
if (!verify_sRGB_blend_a8r8g8b8(bg_row[x], fg_row[x], compare_sRGB_blend_a8r8g8b8(bg_row[x], fg_row[x], shot_row[x],
shot_row[x], x, &max_diff, &diffstat, space);
space)) }
for (i = 0; i < COLOR_CHAN_NUM; i++) {
if (diffstat.rgb[i].min <= -tolerance ||
diffstat.rgb[i].max >= tolerance)
ret = false; ret = false;
} }
testlog("%s max diff: r=%f, g=%f, b=%f\n", rgb_diff_stat_print(&diffstat, __func__, 8);
__func__, max_diff.r, max_diff.g, max_diff.b);
if (dump)
fclose(dump);
return ret; return ret;
} }

@ -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:');
Loading…
Cancel
Save