From: Ville Syrjälä <ville.syrj...@linux.intel.com>

Add a test to try out all the different plane enable/disable
order permutations.

Signed-off-by: Ville Syrjälä <ville.syrj...@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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to