tests/alpha-blending: reference blending

Instead of checking just the monotonicity of the blending results, this
changes the alpha-blending test to compute the reference blend result
itself and then comparing to the compositor result. This way we can be
sure that the compositor implements the exact correct formula and not
something that just looks nice, as verifying the reference images are
actually correct is hard.

The reference image is renamed to follow the fact that this is not
primarily a monotonicity test anymore. The reference image is also
redundant, but I think it has documentary value.

The #if 0'd block of code was very useful in figuring out blending
errors in a future test case, so it is included here. I have a feeling
we are going to need it again.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2021-04-16 17:42:40 +03:00 committed by Pekka Paalanen
parent 129bef50db
commit e70aa1fde2
3 changed files with 118 additions and 8 deletions

View File

@ -25,9 +25,7 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <math.h>
#include "weston-test-client-helper.h"
#include "weston-test-fixture-compositor.h"
@ -125,6 +123,105 @@ fill_alpha_pattern(struct buffer *buf)
}
}
struct color_float {
float r, g, b, a;
};
static struct color_float
a8r8g8b8_to_float(uint32_t v)
{
struct color_float cf;
cf.a = ((v >> 24) & 0xff) / 255.f;
cf.r = ((v >> 16) & 0xff) / 255.f;
cf.g = ((v >> 8) & 0xff) / 255.f;
cf.b = ((v >> 0) & 0xff) / 255.f;
return cf;
}
static void
unpremult_float(struct color_float *cf)
{
if (cf->a == 0.0f) {
cf->r = 0.0f;
cf->g = 0.0f;
cf->b = 0.0f;
} else {
cf->r /= cf->a;
cf->g /= cf->a;
cf->b /= cf->a;
}
}
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;
if (diff < 0.5f / 255.f)
return true;
testlog("x=%d %s: ref %f != dst %f, delta %f\n",
x, chan, ref, dst, dst - ref);
return false;
}
static bool
verify_sRGB_blend_a8r8g8b8(uint32_t bg32, uint32_t fg32, uint32_t dst32,
int x, struct color_float *max_diff)
{
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;
unpremult_float(&bg);
unpremult_float(&fg);
unpremult_float(&dst);
ref.r = (1.0f - fg.a) * bg.r + fg.a * fg.r;
ref.g = (1.0f - fg.a) * bg.g + fg.a * fg.g;
ref.b = (1.0f - fg.a) * bg.b + fg.a * fg.b;
ok = compare_float(ref.r, dst.r, x, "r", &max_diff->r) && ok;
ok = compare_float(ref.g, dst.g, x, "g", &max_diff->g) && ok;
ok = compare_float(ref.b, dst.b, x, "b", &max_diff->b) && ok;
return ok;
}
static uint8_t
red(uint32_t v)
{
@ -171,17 +268,27 @@ get_middle_row(struct buffer *buf)
}
static bool
check_blend_pattern(struct buffer *shot)
check_blend_pattern(struct buffer *bg, struct buffer *fg, struct buffer *shot)
{
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 = { 0.0f, 0.0f, 0.0f, 0.0f };
bool ret = true;
int x;
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))
ret = false;
}
testlog("%s max diff: r=%f, g=%f, b=%f\n",
__func__, max_diff.r, max_diff.g, max_diff.b);
return ret;
}
@ -203,7 +310,7 @@ check_blend_pattern(struct buffer *shot)
* - green is not monotonic
* - blue goes from 0.0 to 1.0, monotonic
*/
TEST(alpha_blend_monotonic)
TEST(alpha_blend)
{
const int width = BLOCK_WIDTH * ALPHA_STEPS;
const int height = BLOCK_WIDTH;
@ -254,10 +361,10 @@ TEST(alpha_blend_monotonic)
shot = capture_screenshot_of_output(client);
assert(shot);
match = verify_image(shot, "alpha_blend_monotonic", 0, NULL, 0);
match = verify_image(shot, "alpha_blend", 0, NULL, 0);
assert(match);
assert(check_blend_pattern(shot));
assert(check_blend_pattern(bg, fg, shot));
buffer_destroy(shot);
wl_subsurface_destroy(sub);

View File

@ -118,7 +118,10 @@ dep_zucmain = declare_dependency(
)
tests = [
{ 'name': 'alpha-blending', },
{
'name': 'alpha-blending',
'dep_objs': dep_libm,
},
{ 'name': 'bad-buffer', },
{ 'name': 'buffer-transforms', },
{ 'name': 'color-manager', },

View File

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B