Ask from kernel about supported modes for each plane and try setting
them on display and verify functionality with crc.

DRM_FORMAT_ARGB8888 and DRM_FORMAT_ABGR8888 skip crc testing on
primary and overlay planes because they produce incorrect crcs from
hardware. DRM_FORMAT_ARGB8888 is tested on cursor plane.

There is preparation for planar formats but I didn't see stable
implementation yet so it has holes.

Signed-off-by: Juha-Pekka Heikkila <juhapekka.heikk...@gmail.com>
---

This is tested on HSW and SKL. There are pieces to support NV12 but it was
not succesfully tested anywhere, probably need work still.

 tests/Makefile.sources          |   1 +
 tests/kms_available_modes_crc.c | 471 ++++++++++++++++++++++++++++++++++++++++
 tests/meson.build               |   1 +
 3 files changed, 473 insertions(+)
 create mode 100644 tests/kms_available_modes_crc.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 870c909..9b804fd 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -171,6 +171,7 @@ TESTS_progs = \
        kms_atomic \
        kms_atomic_interruptible \
        kms_atomic_transition \
+       kms_available_modes_crc \
        kms_busy \
        kms_ccs \
        kms_chv_cursor_fail \
diff --git a/tests/kms_available_modes_crc.c b/tests/kms_available_modes_crc.c
new file mode 100644
index 0000000..206edbc
--- /dev/null
+++ b/tests/kms_available_modes_crc.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright © 2018 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 "drm_mode.h"
+#include "drm_fourcc.h"
+#include "igt.h"
+#include <sys/ioctl.h>
+
+IGT_TEST_DESCRIPTION("CRC test all different plane modes which kernel 
advertises.");
+
+typedef struct {
+       int gfx_fd;
+       igt_display_t display;
+       enum igt_commit_style commit;
+
+       struct igt_fb fb;
+       struct igt_fb primary_fb;
+
+       char format_name[5];
+       bool separateprimaryplane;
+
+       uint32_t gem_handle;
+       unsigned int size;
+       unsigned char* buf;
+
+       /*
+        * comparison crcs
+        */
+       igt_crc_t *cursor_crc;
+       igt_crc_t *fullscreen_crc;
+} data_t;
+
+static int do_write(int fd, int handle, void *buf, int offset, int size)
+{
+       struct drm_i915_gem_pwrite write;
+       memset(&write, 0x00, sizeof(write));
+       write.handle = handle;
+       write.data_ptr = (uintptr_t)buf;
+       write.size = size;
+       write.offset = offset;
+       return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &write);
+}
+
+static void generate_comparison_crc_list(data_t *data, igt_output_t *output,
+                                       enum pipe pipe)
+{
+       drmModeModeInfo *mode;
+       uint64_t w, h, c;
+       int fbid;
+       cairo_t *cr;
+       igt_pipe_crc_t *pipe_crc;
+       igt_plane_t *primary;
+
+
+       igt_output_set_pipe(output, pipe);
+
+       mode = igt_output_get_mode(output);
+       fbid = igt_create_color_fb(data->gfx_fd,
+                                  mode->hdisplay,
+                                  mode->vdisplay,
+                                  DRM_FORMAT_XRGB8888,
+                                  LOCAL_DRM_FORMAT_MOD_NONE,
+                                  0, 0, 0,
+                                  &data->primary_fb);
+
+       igt_assert(fbid);
+
+       drmGetCap(data->gfx_fd, DRM_CAP_CURSOR_WIDTH, &w);
+       drmGetCap(data->gfx_fd, DRM_CAP_CURSOR_HEIGHT, &h);
+
+       cr = igt_get_cairo_ctx(data->gfx_fd, &data->primary_fb);
+       igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
+                           0.0, 0.0, 0.0);
+       igt_paint_color(cr, 0, 0, w, h, 1.0, 1.0, 1.0);
+       igt_assert(cairo_status(cr) == 0);
+
+       primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+       igt_plane_set_fb(primary, &data->primary_fb);
+       igt_display_commit2(&data->display, data->commit);
+
+       pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, 
INTEL_PIPE_CRC_SOURCE_AUTO);
+       igt_pipe_crc_start(pipe_crc);
+       c = igt_pipe_crc_get_crcs(pipe_crc, 3, &data->cursor_crc);
+       igt_assert(c==3);
+       igt_pipe_crc_stop(pipe_crc);
+       igt_pipe_crc_free(pipe_crc);
+
+       igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
+                       1.0, 1.0, 1.0);
+
+       igt_plane_set_fb(primary, &data->primary_fb);
+       igt_display_commit2(&data->display, data->commit);
+
+       pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, 
INTEL_PIPE_CRC_SOURCE_AUTO);
+       igt_pipe_crc_start(pipe_crc);
+       c = igt_pipe_crc_get_crcs(pipe_crc, 3, &data->fullscreen_crc);
+       igt_assert(c==3);
+       igt_pipe_crc_stop(pipe_crc);
+       igt_pipe_crc_free(pipe_crc);
+
+       cairo_destroy(cr);
+       igt_remove_fb(data->gfx_fd, &data->primary_fb);
+}
+
+static bool do_crc_tests(data_t *data, igt_output_t *output, enum pipe pipe,
+                        igt_plane_t *plane, uint32_t format)
+{
+       int i, c;
+       unsigned short* ptemp_16_buf;
+       unsigned int* ptemp_32_buf;
+       igt_crc_t *crcs = NULL;
+       igt_pipe_crc_t *pipe_crc;
+
+       const struct {
+               uint32_t        fourcc;
+               char            zeropadding;
+               enum            { BYTES_PP_1=1, BYTES_PP_2=2, BYTES_PP_4=4,
+                                 NV12, SKIP } bpp;
+               uint32_t        value;
+       } fillers[] = {
+               { DRM_FORMAT_C8, 0, BYTES_PP_1, 0xff},
+               { DRM_FORMAT_RGB565, 0, BYTES_PP_2, 0xffff},
+               { DRM_FORMAT_XRGB8888, 0, BYTES_PP_4, 0xffffffff},
+               { DRM_FORMAT_XBGR8888, 0, BYTES_PP_4, 0xffffffff},
+
+               /*
+                * These two are skipped because blending seems to work
+                * incorrectly with exception of AR24 on cursor plane.
+                * Test still creates the planes, just filling plane
+                * and getting crc is skipped.
+                */
+               { DRM_FORMAT_ARGB8888, 0, SKIP, 0xffffffff},
+               { DRM_FORMAT_ABGR8888, 0, SKIP, 0x00ffffff},
+
+               { DRM_FORMAT_XRGB2101010, 0, BYTES_PP_4, 0xffffffff},
+               { DRM_FORMAT_XBGR2101010, 0, BYTES_PP_4, 0xffffffff},
+
+               { DRM_FORMAT_YUYV, 0, BYTES_PP_4, 0x7fff7fff},
+               { DRM_FORMAT_YVYU, 0, BYTES_PP_4, 0x7fff7fff},
+               { DRM_FORMAT_UYVY, 0, BYTES_PP_4, 0xff7fff7f},
+               { DRM_FORMAT_VYUY, 0, BYTES_PP_4, 0xff7fff7f},
+
+               { DRM_FORMAT_NV12, 0, NV12, 0x7fff},
+
+               { 0, 0, 0, 0 }
+       };
+
+
+       int maxformats = sizeof(fillers)/sizeof(fillers[0])-1;
+
+       for( i = 0; i < maxformats; i++ ) {
+               if( fillers[i].fourcc == format )
+                       break;
+       }
+
+       switch (fillers[i].bpp) {
+       case BYTES_PP_4:
+               ptemp_32_buf = (unsigned int*)data->buf;
+               for (c = 0; c < data->size/4; c++)
+                       ptemp_32_buf[c] = fillers[i].value;
+               break;
+       case BYTES_PP_2:
+               ptemp_16_buf = (unsigned short*)data->buf;
+               for (c = 0; c < data->size/2; c++)
+                       ptemp_16_buf[c] = (unsigned short)fillers[i].value;
+               break;
+       case BYTES_PP_1:
+               memset((void*)data->buf, fillers[i].value, data->size);
+               break;
+       case NV12:
+               memset((void*)data->buf, fillers[i].value&0xff,
+                      data->size*2/3);
+
+               memset((void*)(data->buf+data->size*2/3),
+                      (fillers[i].value>>8)&0xff, data->size/3);
+               break;
+       case SKIP:
+               if (fillers[i].fourcc == DRM_FORMAT_ARGB8888 &&
+                   plane->type == DRM_PLANE_TYPE_CURSOR) {
+               /*
+                * special for cursor plane where blending works correctly.
+                */
+                       ptemp_32_buf = (unsigned int*)data->buf;
+                       for (c = 0; c < data->size/4; c++)
+                               ptemp_32_buf[c] = fillers[i].value;
+                       break;
+               }
+               igt_info("Format %s CRC comparison skipped by design.\n",
+                        (char*)&fillers[i].fourcc);
+
+               return true;
+       default:
+               igt_info("Unsupported mode for test %s\n",
+                        (char*)&fillers[i].fourcc);
+               return true;
+       }
+
+       do_write(data->gfx_fd, data->gem_handle, (void*)data->buf, 0,
+                data->size);
+
+       pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe,
+                                   INTEL_PIPE_CRC_SOURCE_AUTO);
+
+       igt_pipe_crc_start(pipe_crc);
+
+       c = igt_pipe_crc_get_crcs(pipe_crc, 3, &crcs);
+       igt_assert(c==3);
+
+       igt_pipe_crc_stop(pipe_crc);
+       igt_pipe_crc_free(pipe_crc);
+
+       if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+               igt_assert_crc_equal(&crcs[2], &data->fullscreen_crc[2]);
+       } else {
+               igt_assert_crc_equal(&crcs[2], &data->cursor_crc[2]);
+       }
+
+       free(crcs);
+       return true;
+}
+
+
+static bool setup_fb(data_t *data, igt_output_t *output, enum pipe pipe,
+                    igt_plane_t *plane, uint32_t format)
+{
+       uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE;
+       drmModeModeInfo *mode;
+       unsigned int stride;
+       uint64_t w, h;
+       int bpp;
+       int ret;
+       uint32_t offsets[4];
+
+       bpp = 32; //cheating! Don't really care as long as its enough.
+
+       mode = igt_output_get_mode(output);
+       if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+               w = mode->hdisplay ;
+               h = mode->vdisplay;
+       } else {
+               drmGetCap(data->gfx_fd, DRM_CAP_CURSOR_WIDTH, &w);
+               drmGetCap(data->gfx_fd, DRM_CAP_CURSOR_HEIGHT, &h);
+       }
+
+       for (stride = 512; stride < (w * bpp / 8); stride *= 2)
+               ;
+       for (data->size = 1024*1024; data->size < stride * h; data->size *= 2)
+               ;
+
+       data->gem_handle = gem_create(data->gfx_fd, data->size);
+       ret = __gem_set_tiling(data->gfx_fd, data->gem_handle,
+                              I915_TILING_NONE, stride);
+
+       igt_assert_eq(ret, 0);
+
+       switch(format) {
+       case DRM_FORMAT_NV12:
+               offsets[0] = 0;
+               offsets[1] = data->size*2/3;
+
+               ret = __kms_addfb(data->gfx_fd, data->gem_handle, w, h,
+                                 stride, format, tiling,
+                                 (uint32_t *)&offsets,
+                                 LOCAL_DRM_MODE_FB_MODIFIERS,
+                                 &data->fb.fb_id);
+               break;
+       default:
+               ret = __kms_addfb(data->gfx_fd, data->gem_handle, w, h,
+                                 stride, format, tiling, NULL,
+                                 LOCAL_DRM_MODE_FB_MODIFIERS,
+                                 &data->fb.fb_id);
+               break;
+       }
+
+       if(ret < 0) {
+               igt_info("Creating fb for format %s failed, return code %d\n",
+                        (char*)&data->format_name, ret);
+
+               return false;
+       }
+
+       data->fb.width = w;
+       data->fb.height = h;
+       data->fb.gem_handle = data->gem_handle;
+
+       igt_plane_set_fb(plane, &data->fb);
+       igt_fb_set_size(&data->fb, plane, w, h);
+       igt_plane_set_size(plane, w, h);
+       igt_fb_set_position(&data->fb, plane, 0, 0);
+       igt_display_commit2(&data->display, data->commit);
+       return true;
+}
+
+
+static void remove_fb(data_t* data, igt_output_t* output, igt_plane_t* plane)
+{
+       if (data->separateprimaryplane) {
+               igt_plane_t* primary = igt_output_get_plane_type(output,
+                                                                
DRM_PLANE_TYPE_PRIMARY);
+               igt_plane_set_fb(primary, NULL);
+               igt_remove_fb(data->gfx_fd, &data->primary_fb);
+               igt_display_commit2(&data->display, data->commit);
+               data->separateprimaryplane = false;
+       }
+
+       igt_remove_fb(data->gfx_fd, &data->fb);
+       igt_display_commit2(&data->display, data->commit);
+       free(data->buf);
+}
+
+static bool prepare_crtc(data_t *data, igt_output_t *output, enum pipe pipe,
+                        igt_plane_t *plane, uint32_t format)
+{
+       drmModeModeInfo *mode;
+       igt_plane_t *primary;
+
+       igt_output_set_pipe(output, pipe);
+
+       if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
+               mode = igt_output_get_mode(output);
+               igt_create_color_fb(data->gfx_fd,
+                                   mode->hdisplay, mode->vdisplay,
+                                   DRM_FORMAT_XRGB8888,
+                                   LOCAL_DRM_FORMAT_MOD_NONE,
+                                   0, 0, 0,
+                                   &data->primary_fb);
+               primary = igt_output_get_plane_type(output,
+                                                   DRM_PLANE_TYPE_PRIMARY);
+
+               igt_plane_set_fb(primary, &data->primary_fb);
+               igt_display_commit2(&data->display, data->commit);
+
+               data->separateprimaryplane = true;
+       }
+
+       if (!setup_fb(data, output, pipe, plane, format))
+               return false;
+
+       data->buf = (unsigned char*)malloc(data->size);
+       return true;
+}
+
+static int
+test_one_mode(data_t* data, igt_output_t *output, igt_plane_t* plane,
+             enum pipe pipe, int mode)
+{
+       if ( prepare_crtc(data, output, pipe, plane, mode)){
+               do_crc_tests(data, output, pipe, plane, mode);
+
+               remove_fb(data, output, plane);
+               return 0;
+       }
+       return 1;
+}
+
+static void
+test_available_modes(data_t* data)
+{
+       igt_output_t *output;
+       igt_plane_t *plane;
+       int* u32ptr_formats = NULL;
+       int modeindex;
+       enum pipe pipe;
+       struct drm_mode_get_plane one_plane = {};
+       int invalids = 0;
+
+       char    planetype[3][8] = {"OVERLAY\0", "PRIMARY\0", "CURSOR\0" };
+
+       for_each_pipe_with_valid_output(&data->display, pipe, output) {
+               igt_output_set_pipe(output, pipe);
+
+               /*
+                * regenerate comparison crcs for each pipe just in case.
+                */
+               generate_comparison_crc_list(data, output, pipe);
+
+               for_each_plane_on_pipe(&data->display, pipe, plane) {
+
+                       memset((void*)&one_plane, 0,
+                              sizeof(struct drm_mode_get_plane));
+                       one_plane.plane_id = plane->drm_plane->plane_id;
+                       /*
+                        * first call again to know how much space needed,
+                        * second call to get list of supported modes.
+                        */
+                       igt_ioctl(data->gfx_fd, DRM_IOCTL_MODE_GETPLANE,
+                                 &one_plane);
+                       igt_assert(one_plane.count_format_types > 0);
+
+                       u32ptr_formats = 
(int*)calloc(one_plane.count_format_types,
+                                                     sizeof(int));
+
+                       one_plane.format_type_ptr = (__u64)u32ptr_formats;
+                       igt_ioctl(data->gfx_fd, DRM_IOCTL_MODE_GETPLANE,
+                                 &one_plane);
+
+                       for (modeindex = 0;
+                            modeindex < one_plane.count_format_types;
+                            modeindex++) {
+                               data->format_name[0] = 
u32ptr_formats[modeindex]&0xff;
+                               data->format_name[1] = 
(u32ptr_formats[modeindex]>>8)&0xff;
+                               data->format_name[2] = 
(u32ptr_formats[modeindex]>>16)&0xff;
+                               data->format_name[3] = 
(u32ptr_formats[modeindex]>>24)&0xff;
+
+                               igt_info("Testing connector %s using pipe %s" \
+                                        " plane index %d type %s mode %s\n",
+                                        igt_output_name(output),
+                                        kmstest_pipe_name(pipe),
+                                        plane->index,
+                                        planetype[plane->type],
+                                        (char*)&data->format_name);
+
+                               invalids += test_one_mode(data, output,
+                                                         plane, pipe,
+                                                         
u32ptr_formats[modeindex]);
+                       }
+
+                       free((void*)one_plane.format_type_ptr);
+               }
+               free(data->cursor_crc);
+               free(data->fullscreen_crc);
+       }
+
+       igt_assert(invalids == 0);
+}
+
+igt_main
+{
+       data_t data = {};
+
+       igt_skip_on_simulation();
+
+       igt_fixture {
+               data.gfx_fd = drm_open_driver_master(DRIVER_INTEL);
+               kmstest_set_vt_graphics_mode();
+               igt_require_pipe_crc(data.gfx_fd);
+               igt_display_init(&data.display, data.gfx_fd);
+       }
+
+       data.commit = data.display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY;
+
+       igt_subtest("available_mode_test_crc") {
+               test_available_modes(&data);
+       }
+
+       igt_fixture {
+               kmstest_restore_vt_mode();
+               igt_display_fini(&data.display);
+       }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 521a4c4..6b45111 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -149,6 +149,7 @@ test_progs = [
        'kms_atomic',
        'kms_atomic_interruptible',
        'kms_atomic_transition',
+       'kms_available_modes_crc',
        'kms_busy',
        'kms_ccs',
        'kms_chv_cursor_fail',
-- 
2.7.4

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

Reply via email to