diff options
-rw-r--r-- | lib/igt_chamelium.c | 143 | ||||
-rw-r--r-- | lib/igt_chamelium.h | 5 | ||||
-rw-r--r-- | tests/chamelium.c | 77 |
3 files changed, 167 insertions, 58 deletions
diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c index 93392af72..abcdc522c 100644 --- a/lib/igt_chamelium.c +++ b/lib/igt_chamelium.c @@ -94,6 +94,13 @@ struct chamelium_frame_dump { struct chamelium_port *port; }; +struct chamelium_fb_crc_async_data { + cairo_surface_t *fb_surface; + + pthread_t thread_id; + igt_crc_t *ret; +}; + struct chamelium { xmlrpc_env env; xmlrpc_client *client; @@ -998,6 +1005,142 @@ int chamelium_get_frame_limit(struct chamelium *chamelium, return ret; } +static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer, int width, + int height, int k, int m) +{ + unsigned char r, g, b; + uint64_t sum = 0; + uint64_t count = 0; + uint64_t value; + uint32_t hash; + int index; + int i; + + for (i=0; i < width * height; i++) { + if ((i % m) != k) + continue; + + index = i * 4; + + r = buffer[index + 2]; + g = buffer[index + 1]; + b = buffer[index + 0]; + + value = r | (g << 8) | (b << 16); + sum += ++count * value; + } + + hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >> 48)) & 0xffff; + + return hash; +} + +static void chamelium_do_calculate_fb_crc(cairo_surface_t *fb_surface, + igt_crc_t *out) +{ + unsigned char *buffer; + int n = 4; + int w, h; + int i, j; + + buffer = cairo_image_surface_get_data(fb_surface); + w = cairo_image_surface_get_width(fb_surface); + h = cairo_image_surface_get_height(fb_surface); + + for (i = 0; i < n; i++) { + j = n - i - 1; + out->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n); + } + + out->n_words = n; +} + +/** + * chamelium_calculate_fb_crc: + * @fd: The drm file descriptor + * @fb: The framebuffer to calculate the CRC for + * + * Calculates the CRC for the provided framebuffer, using the Chamelium's CRC + * algorithm. This calculates the CRC in a synchronous fashion. + * + * Returns: The calculated CRC + */ +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb) +{ + igt_crc_t *ret = calloc(1, sizeof(igt_crc_t)); + cairo_surface_t *fb_surface; + + /* Get the cairo surface for the framebuffer */ + fb_surface = igt_get_cairo_surface(fd, fb); + + chamelium_do_calculate_fb_crc(fb_surface, ret); + + return ret; +} + +static void *chamelium_calculate_fb_crc_async_work(void *data) +{ + struct chamelium_fb_crc_async_data *fb_crc; + + fb_crc = (struct chamelium_fb_crc_async_data *) data; + + chamelium_do_calculate_fb_crc(fb_crc->fb_surface, fb_crc->ret); + + return NULL; +} + +/** + * chamelium_calculate_fb_crc_launch: + * @fd: The drm file descriptor + * @fb: The framebuffer to calculate the CRC for + * + * Launches the CRC calculation for the provided framebuffer, using the + * Chamelium's CRC algorithm. This calculates the CRC in an asynchronous + * fashion. + * + * The returned structure should be passed to a subsequent call to + * chamelium_calculate_fb_crc_result. It should not be freed. + * + * Returns: An intermediate structure for the CRC calculation work. + */ +struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd, + struct igt_fb *fb) +{ + struct chamelium_fb_crc_async_data *fb_crc; + + fb_crc = calloc(1, sizeof(struct chamelium_fb_crc_async_data)); + fb_crc->ret = calloc(1, sizeof(igt_crc_t)); + + /* Get the cairo surface for the framebuffer */ + fb_crc->fb_surface = igt_get_cairo_surface(fd, fb); + + pthread_create(&fb_crc->thread_id, NULL, + chamelium_calculate_fb_crc_async_work, fb_crc); + + return fb_crc; +} + +/** + * chamelium_calculate_fb_crc_result: + * @fb_crc: An intermediate structure with thread-related information + * + * Blocks until the asynchronous CRC calculation is finished, and then returns + * its result. + * + * Returns: The calculated CRC + */ +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc) +{ + igt_crc_t *ret; + + pthread_join(fb_crc->thread_id, NULL); + + ret = fb_crc->ret; + free(fb_crc); + + return ret; +} + static unsigned int chamelium_get_port_type(struct chamelium *chamelium, struct chamelium_port *port) { diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h index 81322ad2e..2bfbfdc72 100644 --- a/lib/igt_chamelium.h +++ b/lib/igt_chamelium.h @@ -36,6 +36,7 @@ struct chamelium; struct chamelium_port; struct chamelium_frame_dump; +struct chamelium_fb_crc_async_data; struct chamelium *chamelium_init(int drm_fd); void chamelium_deinit(struct chamelium *chamelium); @@ -92,6 +93,10 @@ struct chamelium_frame_dump *chamelium_port_dump_pixels(struct chamelium *chamel struct chamelium_port *port, int x, int y, int w, int h); +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb); +struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd, + struct igt_fb *fb); +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc); int chamelium_get_captured_frame_count(struct chamelium *chamelium); int chamelium_get_frame_limit(struct chamelium *chamelium, struct chamelium_port *port, diff --git a/tests/chamelium.c b/tests/chamelium.c index 0528ffb37..ecd0434ce 100644 --- a/tests/chamelium.c +++ b/tests/chamelium.c @@ -49,43 +49,6 @@ typedef struct { #define HPD_TOGGLE_COUNT_VGA 5 #define HPD_TOGGLE_COUNT_DP_HDMI 15 -/* Pre-calculated CRCs for the pattern fb, for all the modes in the default - * chamelium edid - */ -struct crc_entry { - int width; - int height; - igt_crc_t crc; -}; - -#define CRC_ENTRY(w_, h_, ...) \ - { w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } } - -static const struct crc_entry pattern_fb_crcs[] = { - CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1), - CRC_ENTRY(1280, 720, 0xcec2, 0x4246, 0x6cfd, 0xeb43), - CRC_ENTRY(1024, 768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18), - CRC_ENTRY( 800, 600, 0x6b39, 0x32b6, 0x831a, 0xb03e), - CRC_ENTRY( 640, 480, 0xa121, 0x2473, 0xb150, 0x8c47), -}; -#undef CRC_ENTRY - -static const igt_crc_t * -get_precalculated_crc(struct chamelium_port *port, int w, int h) -{ - int i; - const struct crc_entry *entry; - - for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) { - entry = &pattern_fb_crcs[i]; - - if (entry->width == w && entry->height == h) - return &entry->crc; - } - - return NULL; -} - static void get_connectors_link_status_failed(data_t *data, bool *link_status_failed) { @@ -463,7 +426,8 @@ test_display_crc_single(data_t *data, struct chamelium_port *port) igt_output_t *output; igt_plane_t *primary; igt_crc_t *crc; - const igt_crc_t *expected_crc; + igt_crc_t *expected_crc; + struct chamelium_fb_crc_async_data *fb_crc; struct igt_fb fb; drmModeModeInfo *mode; drmModeConnector *connector; @@ -486,24 +450,21 @@ test_display_crc_single(data_t *data, struct chamelium_port *port) 0, 0, 0, &fb); igt_assert(fb_id > 0); + fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd, + &fb); enable_output(data, port, output, mode, &fb); - expected_crc = get_precalculated_crc(port, - mode->hdisplay, - mode->vdisplay); - if (!expected_crc) { - igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n", - mode->hdisplay, mode->vdisplay); - goto next; - } - igt_debug("Testing single CRC fetch\n"); + crc = chamelium_get_crc_for_area(data->chamelium, port, 0, 0, 0, 0); + + expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc); + igt_assert_crc_equal(crc, expected_crc); + free(expected_crc); free(crc); -next: disable_output(data, port, output); igt_remove_fb(data->drm_fd, &fb); } @@ -519,7 +480,8 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port) igt_output_t *output; igt_plane_t *primary; igt_crc_t *crc; - const igt_crc_t *expected_crc; + igt_crc_t *expected_crc; + struct chamelium_fb_crc_async_data *fb_crc; struct igt_fb fb; drmModeModeInfo *mode; drmModeConnector *connector; @@ -542,15 +504,10 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port) 0, 0, 0, &fb); igt_assert(fb_id > 0); - enable_output(data, port, output, mode, &fb); + fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd, + &fb); - expected_crc = get_precalculated_crc(port, mode->hdisplay, - mode->vdisplay); - if (!expected_crc) { - igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n", - mode->hdisplay, mode->vdisplay); - goto next; - } + enable_output(data, port, output, mode, &fb); /* We want to keep the display running for a little bit, since * there's always the potential the driver isn't able to keep @@ -561,11 +518,15 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port) &captured_frame_count); igt_debug("Captured %d frames\n", captured_frame_count); + + expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc); + for (j = 0; j < captured_frame_count; j++) igt_assert_crc_equal(&crc[j], expected_crc); + + free(expected_crc); free(crc); -next: disable_output(data, port, output); igt_remove_fb(data->drm_fd, &fb); } |