Commit 8cf32fe0 authored by Paul Kocialkowski's avatar Paul Kocialkowski Committed by Lyude Paul

lib/igt_frame: Add support for analog frame comparison testing

This adds support for analog frame comparison check, as used in VGA.
Since VGA uses a DAC-ADC chain, its data cannot be expected to be pixel
perfect. Thus, it is impossible to uses a CRC check and full frames have
to be analyzed instead. Such an analysis is implemented, based on both
an absolute error threshold and a correlation with the expected error
trend for a DAC-ADC chain. It was tested with a couple encoders and
provides reliable error detection with few false positives.
Signed-off-by: default avatarPaul Kocialkowski <paul.kocialkowski@linux.intel.com>
Reviewed-by: Lyude Paul's avatarLyude <lyude@redhat.com>
parent c42ab4d2
......@@ -181,6 +181,8 @@ PKG_CHECK_MODULES(GLIB, [glib-2.0], [glib=yes], [glib=no])
if test x"$glib" = xyes; then
AC_DEFINE(HAVE_GLIB,1,[Enable glib support])
fi
PKG_CHECK_MODULES(GSL, [gsl], [gsl=yes], [gsl=no])
AM_CONDITIONAL(HAVE_GSL, [test "x$gsl" = xyes])
# for chamelium
AC_ARG_ENABLE(chamelium, AS_HELP_STRING([--disable-chamelium],
......
......@@ -29,12 +29,20 @@ lib_source_list += \
$(NULL)
endif
if HAVE_GSL
lib_source_list += \
igt_frame.c \
igt_frame.h \
$(NULL)
endif
AM_CPPFLAGS = -I$(top_srcdir)
AM_CFLAGS = \
$(CWARNFLAGS) \
$(DRM_CFLAGS) \
$(PCIACCESS_CFLAGS) \
$(LIBUNWIND_CFLAGS) \
$(GSL_CFLAGS) \
$(KMOD_CFLAGS) \
$(PROCPS_CFLAGS) \
$(DEBUG_CFLAGS) \
......@@ -54,6 +62,7 @@ libintel_tools_la_LIBADD = \
$(DRM_LIBS) \
$(PCIACCESS_LIBS) \
$(PROCPS_LIBS) \
$(GSL_LIBS) \
$(KMOD_LIBS) \
$(CAIRO_LIBS) \
$(LIBUDEV_LIBS) \
......
......@@ -83,8 +83,6 @@ lib_source_list = \
uwildmat/uwildmat.c \
igt_kmod.c \
igt_kmod.h \
igt_frame.c \
igt_frame.h \
$(NULL)
.PHONY: version.h.tmp
......
......@@ -29,6 +29,8 @@
#include <fcntl.h>
#include <pixman.h>
#include <cairo.h>
#include <gsl/gsl_statistics_double.h>
#include <gsl/gsl_fit.h>
#include "igt.h"
......@@ -135,3 +137,132 @@ void igt_write_compared_frames_to_png(cairo_surface_t *reference,
close(fd);
}
/**
* igt_check_analog_frame_match:
* @reference: The reference cairo surface
* @capture: The captured cairo surface
*
* Checks that the analog image contained in the chamelium frame dump matches
* the given framebuffer.
*
* In order to determine whether the frame matches the reference, the following
* reasoning is implemented:
* 1. The absolute error for each color value of the reference is collected.
* 2. The average absolute error is calculated for each color value of the
* reference and must not go above 60 (23.5 % of the total range).
* 3. A linear fit for the average absolute error from the pixel value is
* calculated, as a DAC-ADC chain is expected to have a linear error curve.
* 4. The linear fit is correlated with the actual average absolute error for
* the frame and the correlation coefficient is checked to be > 0.985,
* indicating a match with the expected error trend.
*
* Most errors (e.g. due to scaling, rotation, color space, etc) can be
* reliably detected this way, with a minimized number of false-positives.
* However, the brightest values (250 and up) are ignored as the error trend
* is often not linear there in practice due to clamping.
*
* Returns: a boolean indicating whether the frames match
*/
bool igt_check_analog_frame_match(cairo_surface_t *reference,
cairo_surface_t *capture)
{
pixman_image_t *reference_src, *capture_src;
int w, h;
int error_count[3][256][2] = { 0 };
double error_average[4][250];
double error_trend[250];
double c0, c1, cov00, cov01, cov11, sumsq;
double correlation;
unsigned char *reference_pixels, *capture_pixels;
unsigned char *p;
unsigned char *q;
bool match = true;
int diff;
int x, y;
int i, j;
w = cairo_image_surface_get_width(reference);
h = cairo_image_surface_get_height(reference);
reference_src = pixman_image_create_bits(
PIXMAN_x8r8g8b8, w, h,
(void*)cairo_image_surface_get_data(reference),
cairo_image_surface_get_stride(reference));
reference_pixels = (unsigned char *) pixman_image_get_data(reference_src);
capture_src = pixman_image_create_bits(
PIXMAN_x8r8g8b8, w, h,
(void*)cairo_image_surface_get_data(capture),
cairo_image_surface_get_stride(capture));
capture_pixels = (unsigned char *) pixman_image_get_data(capture_src);
/* Collect the absolute error for each color value */
for (x = 0; x < w; x++) {
for (y = 0; y < h; y++) {
p = &capture_pixels[(x + y * w) * 4];
q = &reference_pixels[(x + y * w) * 4];
for (i = 0; i < 3; i++) {
diff = (int) p[i] - q[i];
if (diff < 0)
diff = -diff;
error_count[i][q[i]][0] += diff;
error_count[i][q[i]][1]++;
}
}
}
/* Calculate the average absolute error for each color value */
for (i = 0; i < 250; i++) {
error_average[0][i] = i;
for (j = 1; j < 4; j++) {
error_average[j][i] = (double) error_count[j-1][i][0] /
error_count[j-1][i][1];
if (error_average[j][i] > 60) {
igt_warn("Error average too high (%f)\n",
error_average[j][i]);
match = false;
goto complete;
}
}
}
/*
* Calculate error trend from linear fit.
* A DAC-ADC chain is expected to have a linear absolute error on
* most of its range
*/
for (i = 1; i < 4; i++) {
gsl_fit_linear((const double *) &error_average[0], 1,
(const double *) &error_average[i], 1, 250,
&c0, &c1, &cov00, &cov01, &cov11, &sumsq);
for (j = 0; j < 250; j++)
error_trend[j] = c0 + j * c1;
correlation = gsl_stats_correlation((const double *) &error_trend,
1,
(const double *) &error_average[i],
1, 250);
if (correlation < 0.985) {
igt_warn("Error with reference not correlated (%f)\n",
correlation);
match = false;
goto complete;
}
}
complete:
pixman_image_unref(reference_src);
pixman_image_unref(capture_src);
return match;
}
......@@ -39,5 +39,7 @@ void igt_write_compared_frames_to_png(cairo_surface_t *reference,
cairo_surface_t *capture,
const char *reference_suffix,
const char *capture_suffix);
bool igt_check_analog_frame_match(cairo_surface_t *reference,
cairo_surface_t *capture);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment