[Intel-gfx] [PATCH i-g-t] tests: Add kms_plane_blinker
ville.syrjala at linux.intel.com
ville.syrjala at linux.intel.com
Mon Dec 12 20:35:31 UTC 2016
From: Ville Syrjälä <ville.syrjala at linux.intel.com>
Add a test to try out all the different plane enable/disable
order permutations.
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
tests/Makefile.sources | 1 +
tests/kms_plane_blinker.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 530 insertions(+)
create mode 100644 tests/kms_plane_blinker.c
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 04dd2d58612f..9c60bb90335d 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -110,6 +110,7 @@ TESTS_progs_M = \
kms_pipe_color \
kms_pipe_crc_basic \
kms_plane \
+ kms_plane_blinker \
kms_plane_multiple \
kms_properties \
kms_psr_sink_crc \
diff --git a/tests/kms_plane_blinker.c b/tests/kms_plane_blinker.c
new file mode 100644
index 000000000000..c6dace1121b5
--- /dev/null
+++ b/tests/kms_plane_blinker.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "igt.h"
+
+IGT_TEST_DESCRIPTION("Test all plane enable/disable sequence permutations.");
+
+#define __FAC_0 1
+#define __FAC_1 1
+#define __FAC_2 (2*__FAC_1)
+#define __FAC_3 (3*__FAC_2)
+#define __FAC_4 (4*__FAC_3)
+#define _FAC(n) __FAC_ ## n
+#define FAC(n) _FAC(n)
+
+#define __SUB_4_0 4
+#define __SUB_4_1 3
+#define __SUB_4_2 2
+#define __SUB_4_3 1
+#define __SUB_4_4 0
+#define _SUB(a,b) __SUB_ ## a ## _ ## b
+#define SUB(a,b) _SUB(a,b)
+
+#define C(k,n) (FAC(k) / (FAC(SUB(k, n)) * FAC(n)))
+
+/* all combinations */
+#define NUM_REF_CRCS (C(4,0) + C(4,1) + C(4,2) + C(4,3) + C(4,4))
+
+typedef struct {
+ int drm_fd;
+ igt_display_t display;
+ igt_output_t *output;
+ enum pipe pipe;
+ igt_pipe_crc_t *pipe_crc;
+ igt_crc_t ref_crc[NUM_REF_CRCS];
+ uint8_t ref_crc_active_planes[NUM_REF_CRCS];
+ int num_ref_crcs;
+ uint32_t devid;
+ unsigned int delay_us;
+ unsigned int timeout_ms;
+ struct igt_fb ref_fb;
+ struct igt_fb fb[4];
+ igt_plane_t *plane[4];
+ uint8_t num_planes;
+ uint8_t active_plane[4];
+ uint8_t num_active_planes;
+} data_t;
+
+static unsigned int gettime_ms(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+
+static const struct {
+ float r, g, b;
+} colors[] = {
+ { 1.0f, 0.0f, 0.0f },
+ { 0.0f, 1.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f },
+ { 0.0f, 1.0f, 1.0f },
+ { 1.0f, 0.0f, 1.0f },
+ { 1.0f, 1.0f, 0.0f },
+};
+
+static uint32_t plane_format(data_t *data, int plane)
+{
+ if (plane == data->num_planes - 1)
+ return DRM_FORMAT_ARGB8888;
+ else
+ return DRM_FORMAT_XRGB8888;
+}
+
+static int plane_x(int plane)
+{
+ return plane * 100;
+}
+
+static int plane_y(int plane)
+{
+ return plane * 100;
+}
+
+static int plane_width(data_t *data, int plane)
+{
+ drmModeModeInfo *mode = igt_output_get_mode(data->output);
+
+ if (plane == 0)
+ return mode->hdisplay;
+ else if (plane == data->num_planes - 1)
+ return 64;
+ else
+ return mode->hdisplay / 2;
+}
+
+static int plane_height(data_t *data, int plane)
+{
+ drmModeModeInfo *mode = igt_output_get_mode(data->output);
+
+ if (plane == 0)
+ return mode->vdisplay;
+ else if (plane == data->num_planes - 1)
+ return 64;
+ else
+ return mode->vdisplay / 2;
+}
+
+static igt_crc_t *find_ref_crc(data_t *data, uint8_t active_planes)
+{
+ int i;
+
+ for (i = 0; i < data->num_ref_crcs; i++) {
+ if (data->ref_crc_active_planes[i] == active_planes)
+ return &data->ref_crc[i];
+ }
+
+ return NULL;
+}
+
+static void generate_ref_crc(data_t *data, int num_active_planes)
+{
+ drmModeModeInfo *mode;
+ cairo_t *cr;
+ int i;
+
+ mode = igt_output_get_mode(data->output);
+
+ data->ref_crc_active_planes[data->num_ref_crcs] = 0;
+
+ cr = igt_get_cairo_ctx(data->drm_fd, &data->ref_fb);
+
+ igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
+ 0.0, 0.0, 0.0);
+
+ for (i = 0; i < num_active_planes; i++) {
+ int plane = data->active_plane[i];
+ int w, h;
+ int x, y;
+
+ data->ref_crc_active_planes[data->num_ref_crcs] |= 1 << plane;
+
+ x = plane_x(plane);
+ y = plane_y(plane);
+ w = plane_width(data, plane);
+ h = plane_height(data, plane);
+
+ cairo_save(cr);
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_clip(cr);
+
+ igt_paint_color(cr, x, y, w, h,
+ colors[plane].r, colors[plane].g, colors[plane].b);
+ cairo_translate(cr, x, y);
+ igt_paint_test_pattern(cr, w, h);
+ cairo_restore(cr);
+ }
+
+ igt_assert(cairo_status(cr) == 0);
+ cairo_destroy(cr);
+
+ igt_wait_for_vblank(data->drm_fd, data->pipe);
+
+ igt_assert(data->num_ref_crcs < NUM_REF_CRCS);
+ igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc[data->num_ref_crcs]);
+ data->num_ref_crcs++;
+}
+
+static void do_combination(data_t *data, int plane, int idx,
+ int num_active_planes)
+{
+ if (idx == num_active_planes) {
+ generate_ref_crc(data, num_active_planes);
+ return;
+ }
+
+ for (; plane < data->num_planes; plane++) {
+ data->active_plane[idx] = plane;
+ do_combination(data, plane + 1, idx + 1, num_active_planes);
+ }
+}
+
+static bool igt_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+ return a->n_words == b->n_words &&
+ memcmp(a->crc, b->crc, sizeof(a->crc[0]) * a->n_words) == 0;
+}
+
+static void generate_ref_crcs(data_t *data)
+{
+ int num_active_planes, i, j;
+
+ data->num_ref_crcs = 0;
+
+ /* ref crc for 0 active planes */
+ for (num_active_planes = 0;
+ num_active_planes <= data->num_active_planes;
+ num_active_planes++)
+ do_combination(data, 0, 0, num_active_planes);
+
+ for (i = 0; i < data->num_ref_crcs; i++) {
+ for (j = i + 1; j < data->num_ref_crcs; j++) {
+ if (igt_crc_equal(&data->ref_crc[i], &data->ref_crc[j]))
+ break;
+ }
+ if (j < data->num_ref_crcs) {
+ igt_warn("reference CRCs not unique\n");
+ break;
+ }
+ }
+}
+
+static bool prepare_crtc(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ drmModeModeInfo *mode;
+ int i;
+
+ /* select the pipe we want to use */
+ igt_output_set_pipe(data->output, data->pipe);
+ igt_display_commit(display);
+
+ if (!data->output->valid) {
+ igt_output_set_pipe(data->output, PIPE_ANY);
+ igt_display_commit(display);
+ return false;
+ }
+
+ mode = igt_output_get_mode(data->output);
+
+ igt_create_color_fb(data->drm_fd,
+ mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ 1.0, 1.0, 1.0,
+ &data->ref_fb);
+
+ for (i = 0; i < data->num_planes; i++) {
+ igt_create_color_pattern_fb(data->drm_fd,
+ plane_width(data, i), plane_height(data, i),
+ plane_format(data, i), LOCAL_DRM_FORMAT_MOD_NONE,
+ colors[i].r, colors[i].g, colors[i].b,
+ &data->fb[i]);
+
+ data->plane[i] = igt_output_get_plane(data->output, i);
+ }
+
+ igt_plane_set_fb(data->plane[0], &data->ref_fb);
+ igt_display_commit(display);
+
+ /* create the pipe_crc object for this pipe */
+ if (data->pipe_crc)
+ igt_pipe_crc_free(data->pipe_crc);
+ data->pipe_crc = igt_pipe_crc_new_nonblock(data->pipe,
+ INTEL_PIPE_CRC_SOURCE_AUTO);
+
+ generate_ref_crcs(data);
+
+ igt_plane_set_fb(data->plane[0], NULL);
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+
+ igt_remove_fb(data->drm_fd, &data->ref_fb);
+
+ return true;
+}
+
+#define NCRC 10
+
+static void check_crcs(data_t *data, uint8_t active_planes,
+ igt_crc_t *last_ref_crc,
+ igt_crc_t *ref_crc)
+{
+ igt_crc_t *crc;
+ int i, n;
+
+ n = igt_pipe_crc_get_crcs(data->pipe_crc, NCRC, &crc);
+
+ for (i = 0; i < n; i++) {
+ if (!igt_crc_equal(&crc[i], last_ref_crc))
+ break;
+ }
+ for (; i < n; i++)
+ igt_assert_crc_equal(&crc[i], ref_crc);
+
+ free(crc);
+}
+
+static void do_test(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ igt_crc_t *last_ref_crc;
+ unsigned int start;
+ int num;
+
+ igt_info(" Testing planes: none -> ");
+ for (num = 1; num < data->num_active_planes; num++) {
+ int idx;
+
+ igt_info("%d", data->active_plane[0]);
+ for (idx = 1; idx < num; idx++)
+ igt_info(",%d", data->active_plane[idx]);
+ igt_info(" -> ");
+ }
+ for (; num > 0; num--) {
+ int idx;
+
+ igt_info("%d", data->active_plane[0]);
+ for (idx = 1; idx < num; idx++)
+ igt_info(",%d", data->active_plane[idx]);
+ igt_info(" -> ");
+ }
+ igt_info("none\n");
+
+ start = gettime_ms();
+
+ last_ref_crc = find_ref_crc(data, 0);
+
+ igt_pipe_crc_start(data->pipe_crc);
+
+ do {
+ int idx;
+ uint8_t active_planes = 0;
+
+ for (idx = 0; idx < data->num_active_planes; idx++) {
+ int plane = data->active_plane[idx];
+ igt_crc_t *ref_crc;
+
+ active_planes |= 1 << plane;
+
+ ref_crc = find_ref_crc(data, active_planes);
+ igt_assert(ref_crc);
+
+ igt_plane_set_fb(data->plane[plane], &data->fb[plane]);
+ igt_plane_set_position(data->plane[plane],
+ plane_x(plane), plane_y(plane));
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+ usleep(data->delay_us);
+
+ check_crcs(data, active_planes, last_ref_crc, ref_crc);
+ last_ref_crc = ref_crc;
+ }
+
+ igt_assert(active_planes != 0);
+
+ for (idx = data->num_active_planes - 1; idx >= 0; idx--) {
+ int plane = data->active_plane[idx];
+ igt_crc_t *ref_crc;
+
+ active_planes &= ~(1 << plane);
+
+ ref_crc = find_ref_crc(data, active_planes);
+ igt_assert(ref_crc);
+
+ igt_plane_set_fb(data->plane[plane], NULL);
+ igt_display_commit2(display, COMMIT_UNIVERSAL);
+ usleep(data->delay_us);
+
+ check_crcs(data, active_planes, last_ref_crc, ref_crc);
+ last_ref_crc = ref_crc;
+ }
+
+ igt_assert(active_planes == 0);
+ } while (data->timeout_ms > 0 &&
+ gettime_ms() - start < data->timeout_ms);
+
+ igt_pipe_crc_stop(data->pipe_crc);
+}
+
+static void do_permutation(data_t *data,
+ unsigned int available_planes,
+ int idx)
+{
+ int plane;
+
+ if (idx == data->num_active_planes) {
+ do_test(data);
+ return;
+ }
+
+ for (plane = 0; plane < data->num_planes; plane++) {
+ if (!(available_planes & (1 << plane)))
+ continue;
+
+ data->active_plane[idx] = plane;
+ do_permutation(data,
+ available_planes & ~(1 << plane),
+ idx + 1);
+ }
+}
+
+static void test_permutations(data_t *data)
+{
+ do_permutation(data, (1 << data->num_planes) - 1, 0);
+}
+
+static void cleanup_crtc(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ int i;
+
+ igt_pipe_crc_free(data->pipe_crc);
+ data->pipe_crc = NULL;
+
+ for (i = 0; i < data->num_planes; i++) {
+ igt_remove_fb(data->drm_fd, &data->fb[i]);
+ igt_plane_set_fb(data->plane[i], NULL);
+ }
+
+ igt_output_set_pipe(data->output, PIPE_ANY);
+ igt_display_commit(display);
+}
+
+static void test(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ int valid_tests = 0;
+
+ igt_require(data->pipe <= display->n_pipes);
+ igt_require(data->num_active_planes <= display->pipes[data->pipe].n_planes);
+
+ data->num_planes = data->display.pipes[data->pipe].n_planes;
+
+ for_each_connected_output(display, data->output) {
+ if (!prepare_crtc(data))
+ continue;
+
+ valid_tests++;
+
+ igt_info("Beginning %s on pipe %s, connector %s\n",
+ igt_subtest_name(),
+ kmstest_pipe_name(data->pipe),
+ igt_output_name(data->output));
+
+ test_permutations(data);
+
+ igt_info("\n%s on pipe %s, connector %s: PASSED\n\n",
+ igt_subtest_name(),
+ kmstest_pipe_name(data->pipe),
+ igt_output_name(data->output));
+
+ cleanup_crtc(data);
+ }
+
+ igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
+}
+
+static int opt_handler(int opt, int opt_index, void *_data)
+{
+ data_t *data = _data;
+
+ switch (opt) {
+ case 'd':
+ data->delay_us = strtoull(optarg, NULL, 0) * 1000;
+ break;
+ case 't':
+ data->timeout_ms = strtoull(optarg, NULL, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static data_t data;
+
+int main(int argc, char *argv[])
+{
+ static const struct option long_opts[] = {
+ { .name = "delay", .val = 'd', .has_arg = required_argument },
+ { .name = "timeout", .val = 't', .has_arg = required_argument },
+ {}
+ };
+ static const char *help_str =
+ " --delay\t\tDelay (in ms) between each plane enable/disable\n"
+ " --timeout\t\tTimeout (in ms) per connector for each subtest\n";
+
+ data.timeout_ms = 100;
+ data.delay_us = 20000;
+
+ igt_subtest_init_parse_opts(&argc, argv, "", long_opts, help_str,
+ opt_handler, &data);
+
+ data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+ data.devid = intel_get_drm_devid(data.drm_fd);
+
+ igt_require_pipe_crc();
+
+ kmstest_set_vt_graphics_mode();
+
+ igt_display_init(&data.display, data.drm_fd);
+ igt_require(data.display.has_universal_planes);
+
+ for (data.pipe = PIPE_A; data.pipe <= PIPE_C; data.pipe++) {
+ for (data.num_active_planes = 1;
+ data.num_active_planes <= 4; data.num_active_planes++) {
+ igt_subtest_f("pipe-%s-%d-planes",
+ kmstest_pipe_name(data.pipe), data.num_active_planes) {
+ test(&data);
+ }
+ }
+ }
+
+ igt_display_fini(&data.display);
+
+ igt_exit();
+}
--
2.7.4
More information about the Intel-gfx
mailing list