[igt-dev] [PATCH i-g-t] tests/kms_yuv: Add yuv specific tests.

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Tue Mar 5 11:55:02 UTC 2019


Op 01-03-2019 om 07:23 schreef Sharma, Swati2:
> Given review comments just for few cosmetic changes.
>
> On 14-Feb-19 8:59 PM, Maarten Lankhorst via igt-dev wrote:
>> Add tests excercising switching between various scaled/unscaled
>> transitions to and from various nv12 formats, since some of the
>> workarounds mention this may fail.
>>
>> We also add NV12 specific clipping/scaling tests, to make sure
>> that YUV src coordinates are always programmed as a multiple of 2
>> correctly, and verify scaling/clipping works with CRC tests.
>>
>> crop-scale-bug shows a corruption when scaling and cropping at the
>> same time.
>>
>> The subpixel clip test rotates and clips a rectangle on each side,
>> which should produce the same CRC as when that part of the rectangle
>> is hidden by a cursor and a whole 2x2 pixel is hidden.
>>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
>> ---
>>   tests/Makefile.sources |   1 +
>>   tests/kms_yuv.c        | 845 +++++++++++++++++++++++++++++++++++++++++
>>   tests/meson.build      |   1 +
>>   3 files changed, 847 insertions(+)
>>   create mode 100644 tests/kms_yuv.c
>>
>> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
>> index a234fa5dd553..d8eb58a85ed2 100644
>> --- a/tests/Makefile.sources
>> +++ b/tests/Makefile.sources
>> @@ -72,6 +72,7 @@ TESTS_progs = \
>>       kms_universal_plane \
>>       kms_vblank \
>>       kms_vrr \
>> +    kms_yuv \
>>       kms_sequence \
>>       meta_test \
>>       perf \
>> diff --git a/tests/kms_yuv.c b/tests/kms_yuv.c
>> new file mode 100644
>> index 000000000000..9a0483f1631e
>> --- /dev/null
>> +++ b/tests/kms_yuv.c
>> @@ -0,0 +1,845 @@
>> +/*
>> + * Copyright © 2019 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 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.
>> + *
>> + * Authors:
>> + *    Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
>> + */
>> +#include "config.h"
>> +
>> +#include "igt.h"
>> +#include <cairo.h>
>> +#include <errno.h>
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <sys/time.h>
>> +
>> +typedef struct {
>> +    igt_display_t display;
>> +
>> +    igt_pipe_crc_t *pipe_crc;
>> +    struct igt_fb fb[6];
>> +} data_t;
>> +
>> +static bool plane_supports_format(igt_plane_t *plane, uint32_t format)
>> +{
>> +    int i;
>> +
>> +    if (!igt_fb_supported_format(format))
>> +        return false;
>> +
>> +    for (i = 0; i < plane->drm_plane->count_formats; i++)
>> +        if (plane->drm_plane->formats[i] == format)
>> +            return true;
>> +
>> +    return false;
>> +}
>> +
>> +static bool pipe_supports_format(igt_display_t *display, enum pipe pipe, uint32_t format)
>> +{
>> +    igt_plane_t *plane;
>> +
>> +    for_each_plane_on_pipe(display, pipe, plane)
>> +        if (plane_supports_format(plane, format))
>> +            return true;
>> +
>> +    return false;
>> +}
>> +
>> +static void remove_fbs(data_t *data)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < ARRAY_SIZE(data->fb); i++)
>> +        igt_remove_fb(data->display.drm_fd, &data->fb[i]);
>> +}
>> +
>> +static void prepare_crtc(data_t *data, enum pipe pipe, igt_output_t *output)
>> +{
>> +    igt_display_t *display = &data->display;
>> +
>> +    remove_fbs(data);
>> +    igt_display_reset(display);
>> +    igt_output_set_pipe(output, pipe);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +    igt_pipe_crc_free(data->pipe_crc);
>> +    data->pipe_crc = igt_pipe_crc_new(display->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
>> +}
>> +
>> +static void set_fb(igt_plane_t *plane, struct igt_fb *fb, bool scaled)
>> +{
>> +    igt_plane_set_fb(plane, fb);
>> +
>> +    if (scaled && fb)
>> +        igt_fb_set_size(fb, plane, fb->width, 16);
>> +
>> +    if (fb && fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED) {
>> +        igt_plane_set_rotation(plane, IGT_ROTATION_90);
>> +        igt_plane_set_size(plane, fb->height, fb->width);
>> +    } else
>> +        igt_plane_set_rotation(plane, IGT_ROTATION_0);
>> +}
>> +
>> +static void yuv_rgb_switch(data_t *data, enum pipe pipe, igt_output_t *output, bool scaled, unsigned format)
>> +{
>> +    drmModeModeInfo *mode = igt_output_get_mode(output);
>> +    igt_display_t *display = &data->display;
>> +    igt_plane_t *plane;
>> +    int i;
>> +    igt_crc_t ref_crc[4], crc;
>> +
>> +    prepare_crtc(data, pipe, output);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
>> +                  format, LOCAL_I915_FORMAT_MOD_X_TILED,
>> +                  &data->fb[0]);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->vdisplay, mode->hdisplay,
>> +                  format, LOCAL_I915_FORMAT_MOD_Y_TILED,
>> +                  &data->fb[1]);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
>> +                  DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_X_TILED,
>> +                  &data->fb[2]);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->vdisplay, mode->hdisplay,
>> +                  DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_Y_TILED,
>> +                  &data->fb[3]);
>> +
>> +    for_each_plane_on_pipe(display, pipe, plane) {
>> +        if (!plane_supports_format(plane, DRM_FORMAT_XRGB8888))
>> +            continue;
>> +
>> +        /* We only have few scalers, don't use 1 for unused planes */
>> +        if (plane->type != DRM_PLANE_TYPE_CURSOR && !scaled)
>> +            set_fb(plane, &data->fb[3], false);
>> +    }
>> +
>> +    for_each_plane_on_pipe(display, pipe, plane) {
>> +        const int seq[] = {
>> +            2, 0, 2, 1, 3, 1, 3
>> +        };
>> +
>> +        if (!plane_supports_format(plane, format))
>> +            continue;
>> +
>> +        /* Collect reference crc with toggle in between. */
>> +        for (i = 0; i < ARRAY_SIZE(ref_crc); i++) {
>> +            set_fb(plane, &data->fb[i], scaled);
>> +            igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +            igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc[i]);
>> +
>> +            set_fb(plane, NULL, scaled);
>> +            igt_display_commit2(display, COMMIT_ATOMIC);
>> +        }
>> +
>> +        for (i = 0; i < ARRAY_SIZE(seq); i++) {
>> +            int j = seq[i];
>> +
>> +            set_fb(plane, &data->fb[j], scaled);
>> +            igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +            igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
>> +            igt_assert_crc_equal(&ref_crc[j], &crc);
>> +        }
>> +
>> +        /* We only have few scalers, don't use 1 for unused planes */
>> +        if (scaled)
>> +            igt_plane_set_fb(plane, NULL);
>> +    }
>> +}
>> +
>> +#define assert_collected_crc_equal(pipe_crc, crc, ref_crc) \
>> +    do { \
>> +        igt_pipe_crc_get_current(display->drm_fd, pipe_crc, crc);    \
>> +        igt_assert_crc_equal(ref_crc, crc);    \
>> +    } while (0)
>> +
>> +static void set_src_coords(igt_plane_t *plane, struct igt_fb *fb,
>> +               igt_rotation_t rot, int vis, int hidden)
> Should one space come before igt_rotation_t to make it align to igt_plane_t?
>> +{
>> +    switch (rot) {
>> +    case IGT_ROTATION_0:
>> +        igt_fb_set_position(fb, plane, fb->width / 2 - vis, fb->height / 2 - vis);
>> +        break;
>> +    case IGT_ROTATION_90:
>> +        igt_fb_set_position(fb, plane, fb->width / 2 - hidden, fb->height / 2 - vis);
>> +        break;
>> +    case IGT_ROTATION_180:
>> +        igt_fb_set_position(fb, plane, fb->width / 2 - hidden, fb->height / 2 - hidden);
>> +        break;
>> +    case IGT_ROTATION_270:
>> +        igt_fb_set_position(fb, plane, fb->width / 2 - vis, fb->height / 2 - hidden);
>> +        break;
>> +    default: igt_assert(0);
>> +    }
>> +    igt_fb_set_size(fb, plane, vis + hidden, vis + hidden);
>> +}
>> +
>> +static void yuv_valid_width_plane(data_t *data, drmModeModeInfo *mode,
>> +                   igt_plane_t *plane, struct igt_fb *fb,
>> +                   igt_rotation_t rot, igt_crc_t *ref_crc)
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc;
>> +    struct igt_fb *clip_fb = &data->fb[2];
>> +    int i, ret;
>> +
>> +    igt_plane_set_fb(plane, fb);
>> +    igt_plane_set_rotation(plane, rot);
>> +    if (rot & (IGT_ROTATION_90 | IGT_ROTATION_270))
>> +        igt_plane_set_size(plane, fb->height, fb->width);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +    /* Just clipping.. */
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    if (rot & (IGT_ROTATION_90 | IGT_ROTATION_270))
>> +        igt_plane_set_size(plane, clip_fb->height, clip_fb->width);
>> +    igt_plane_set_position(plane, mode->hdisplay - clip_fb->width / 2, mode->vdisplay - clip_fb->height / 2);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +    /* Clipping and scaling. */
>> +    igt_fb_set_position(clip_fb, plane, clip_fb->width / 2 - 16, clip_fb->height / 2 - 16);
>> +    igt_fb_set_size(clip_fb, plane, 32, 32);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +    /* Try nvalid < 8 src visible. */
>> +    set_src_coords(plane, clip_fb, rot, 4, 4);
>> +    igt_display_try_commit2(display, COMMIT_ATOMIC);
>> +
>> +    /* Try different alignments for x/y to see if any hit underruns */
>> +    for (i = 1; i < 4; i++) {
>> +        set_src_coords(plane, clip_fb, rot, 16 + 2 * i, 16 - 2 * i);
>> +        igt_display_commit2(display, COMMIT_ATOMIC);
>> +        assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +        /* And also show more of the screen */
>> +        set_src_coords(plane, clip_fb, rot, 16 + i, 16 + i);
>> +        ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
>> +
>> +        if (ret == -EINVAL) {
>> +            igt_assert(i % 2 || rot == IGT_ROTATION_270 || rot == (IGT_ROTATION_90 | IGT_REFLECT_X));
>> +            continue;
>> +        } else
>> +            igt_assert_eq(ret, 0);
>> +        assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    }
>> +
>> +    /*
>> +     * As a final test, try with 16 src visible, and various invisible
>> +     * components to check clipping doesn't drop the visible src below 16.
>> +     */
>> +    for (i = 0; i < 16; i += 4) {
>> +        set_src_coords(plane, clip_fb, rot, 16, i);
>> +        if (rot & (IGT_ROTATION_90 | IGT_ROTATION_270))
>> +            igt_plane_set_size(plane, (clip_fb->height / 32) * (16 + i),
>> +                       (clip_fb->width / 32) * (16 + i));
>> +        else
>> +            igt_plane_set_size(plane, (clip_fb->width / 32) * (16 + i),
>> +                       (clip_fb->height / 32) * (16 + i));
>> +        igt_display_commit2(display, COMMIT_ATOMIC);
>> +        assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    }
>> +}
>> +
>> +static void yuv_valid_width(data_t *data, enum pipe pipe, igt_output_t *output, unsigned format)
>> +{
>> +    drmModeModeInfo *mode = igt_output_get_mode(output);
>> +    igt_display_t *display = &data->display;
>> +    igt_plane_t *plane;
>> +    struct igt_fb *clip_fb = &data->fb[2];
>> +    struct igt_fb *ref_fb = &data->fb[3];
>> +
>> +    prepare_crtc(data, pipe, output);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
>> +                  format, LOCAL_I915_FORMAT_MOD_X_TILED,
>> +                  &data->fb[0]);
>> +
>> +    igt_create_pattern_fb(display->drm_fd, mode->vdisplay, mode->hdisplay,
>> +                  format, LOCAL_I915_FORMAT_MOD_Y_TILED,
>> +                  &data->fb[1]);
>> +
>> +    igt_create_fb(display->drm_fd, 64, 64, format,
>> +              LOCAL_I915_FORMAT_MOD_Y_TILED, ref_fb);
>> +
>> +    igt_create_fb(display->drm_fd, 2 * ref_fb->width,
>> +              2 * ref_fb->height, format,
>> +              LOCAL_I915_FORMAT_MOD_Y_TILED, clip_fb);
>> +
>> +    igt_pipe_crc_start(data->pipe_crc);
>> +
>> +    for_each_plane_on_pipe(display, pipe, plane) {
>> +        igt_crc_t ref_crc[4];
>> +        cairo_t *cr;
>> +        static const double colors[4][3] = {
>> +            { 1., 0., 0. },
>> +            { 0., 1., 0. },
>> +            { 0., 0., 1. },
>> +            { 1., 1., 1. }
>> +        };
>> +        int i;
>> +
>> +        if (!plane_supports_format(plane, format))
>> +            continue;
>> +
>> +        /* Draw the FB that will be used for clipping tests. */
>> +        cr = igt_get_cairo_ctx(display->drm_fd, clip_fb);
>> +        igt_paint_color(cr, 0, 0, clip_fb->width / 2, clip_fb->height / 2,
>> +                colors[0][0], colors[0][1], colors[0][2]);
>> +
>> +        igt_paint_color(cr, clip_fb->width / 2, 0,
>> +                clip_fb->width / 2, clip_fb->height / 2,
>> +                colors[1][0], colors[1][1], colors[1][2]);
>> +
>> +        igt_paint_color(cr, clip_fb->width / 2, clip_fb->height / 2,
>> +                clip_fb->width / 2, clip_fb->height / 2,
>> +                colors[2][0], colors[2][1], colors[2][2]);
>> +
>> +        igt_paint_color(cr, 0, clip_fb->height / 2,
>> +                clip_fb->width / 2, clip_fb->height / 2,
>> +                colors[3][0], colors[3][1], colors[3][2]);
>> +
>> +        igt_put_cairo_ctx(display->drm_fd, clip_fb, cr);
>> +
>> +        /* Draw all reference FB's to collect the CRC. */
>> +        for (i = 0; i < 4; i++) {
>> +            cr = igt_get_cairo_ctx(display->drm_fd, ref_fb);
>> +            igt_paint_color(cr, 0, 0, ref_fb->width, ref_fb->height,
>> +                    colors[i][0], colors[i][1], colors[i][2]);
>> +            igt_put_cairo_ctx(display->drm_fd, &data->fb[3], cr);
>> +
>> +            if (!i) {
>> +                igt_plane_set_fb(plane, ref_fb);
>> +                igt_plane_set_position(plane, mode->hdisplay - ref_fb->width, mode->vdisplay - ref_fb->height);
>> +                igt_display_commit2(display, COMMIT_ATOMIC);
>> +            } else {
>> +                igt_dirty_fb(display->drm_fd, ref_fb);
>> +                igt_wait_for_vblank(display->drm_fd, pipe);
>> +            }
>> +
>> +            igt_pipe_crc_drain(data->pipe_crc);
>> +            igt_pipe_crc_get_single(data->pipe_crc, &ref_crc[i]);
>> +        }
>> +
>> +        igt_plane_set_fb(plane, NULL);
>> +        igt_plane_set_position(plane, 0, 0);
>> +
>> +        yuv_valid_width_plane(data, mode, plane, &data->fb[0], IGT_ROTATION_0, &ref_crc[0]);
>> +        yuv_valid_width_plane(data, mode, plane, &data->fb[1], IGT_ROTATION_90, &ref_crc[1]);
>> +        yuv_valid_width_plane(data, mode, plane, &data->fb[0], IGT_ROTATION_180, &ref_crc[2]);
>> +        yuv_valid_width_plane(data, mode, plane, &data->fb[1], IGT_ROTATION_270, &ref_crc[3]);
>> +
>> +        igt_plane_set_fb(plane, NULL);
>> +    }
>> +}
>> +
>> +static bool yuv_commit_rotated(igt_display_t *display, igt_rotation_t rot)
>> +{
>> +    if (igt_display_try_commit2(display, COMMIT_ATOMIC) < 0) {
>> +        igt_debug("Skipping rotated test, alignment is wrong.\n");
>> +        return false;
>> +    }
>> +
>> +    return true;
>> +}
>> +
>> +static void yuv_crop_scale_bug_plane(data_t *data, drmModeModeInfo *mode,
>> +                      igt_plane_t *plane, struct igt_fb *fb,
>> +                      igt_rotation_t rot, igt_crc_t *ref_crc)
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc;
>> +    int ofs[] = { 0, 1, -1, 2, -2 };
>> +    int i, j;
>> +
>> +    igt_plane_set_fb(plane, fb);
>> +    igt_plane_set_rotation(plane, rot);
>> +
>> +    igt_plane_set_position(plane, 64, 64);
>> +    igt_plane_set_size(plane, 256, 256);
>> +
>> +    igt_fb_set_position(fb, plane, fb->width / 4, fb->height / 4);
>> +    igt_fb_set_size(fb, plane, fb->width / 2, fb->height / 2);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +    /* Make sure boundaries match */
>> +    igt_fb_set_position(fb, plane, fb->width / 4 - 2, fb->height / 4 - 2);
>> +    igt_fb_set_size(fb, plane, fb->width / 2 + 4, fb->height / 2 + 4);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +    for (i = 1; i < ARRAY_SIZE(ofs); i++) {
>> +        igt_debug("Testing with rot %x and extra %i on the left side\n", rot, ofs[i]);
>> +        igt_fb_set_position(fb, plane, fb->width / 4 + ofs[i], fb->height / 4 - 2);
>> +        igt_fb_set_size(fb, plane, fb->width / 2 + 2 - ofs[i], fb->height / 2 + 4);
>> +        if (yuv_commit_rotated(display, rot))
>> +            assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +        igt_debug("Testing with rot %x and extra %i on the top side\n", rot, ofs[i]);
>> +        igt_fb_set_position(fb, plane, fb->width / 4 - 2, fb->height / 4 + ofs[i]);
>> +        igt_fb_set_size(fb, plane, fb->width / 2 + 4, fb->height / 2 + 2 - ofs[i]);
>> +        if (yuv_commit_rotated(display, rot))
>> +            assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +        igt_debug("Testing with rot %x and extra %i on the right side\n", rot, ofs[i]);
>> +        igt_fb_set_position(fb, plane, fb->width / 4 - 2, fb->height / 4);
>> +        igt_fb_set_size(fb, plane, fb->width / 2 + 2 + ofs[i], fb->height / 2);
>> +        if (yuv_commit_rotated(display, rot))
>> +            assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
>> +        igt_debug("Testing with rot %x and extra %i on the bottom side\n", rot, ofs[i]);
>> +        igt_fb_set_position(fb, plane, fb->width / 4 - 2, fb->height / 4 - 2);
>> +        igt_fb_set_size(fb, plane, fb->width / 2 + 4, fb->height / 2 + 2 + ofs[i]);
>> +        if (yuv_commit_rotated(display, rot))
>> +            assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +
> Extra \n?
>> +    }
>> +
>> +    for (i = 0; i < ARRAY_SIZE(ofs); i++)
>> +        for (j = !i; j < ARRAY_SIZE(ofs); j++) {
>> +            igt_debug("Testing with rot %x and extra (%i, %i) at the edges\n", rot, ofs[i], ofs[j]);
>> +
>> +            igt_fb_set_position(fb, plane, fb->width / 4 + ofs[i], fb->height / 4 + ofs[j]);
>> +            igt_fb_set_size(fb, plane, fb->width / 2 - 2 * ofs[i], fb->height / 2 - 2 * ofs[j]);
>> +
>> +            if (yuv_commit_rotated(display, rot))
>> +                assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +        }
>> +}
>> +
>> +static void draw_clip_fb(igt_display_t *display, struct igt_fb *clip_fb)
>> +{
>> +    cairo_t *cr = igt_get_cairo_ctx(display->drm_fd, clip_fb);
>> +
>> +    igt_paint_color(cr, 0, 0, clip_fb->width, clip_fb->height, .0, .0, .5);
>> +    igt_paint_color(cr, clip_fb->width / 4 - 2, clip_fb->height / 4 - 2,
>> +            clip_fb->width / 2 + 4, clip_fb->height / 2 + 4, 1., 1., 1.);
>> +
>> +    igt_put_cairo_ctx(display->drm_fd, clip_fb, cr);
>> +}
>> +
>> +static void yuv_crop_scale_bug(data_t *data, enum pipe pipe, igt_output_t *output, unsigned format)
>> +{
>> +    drmModeModeInfo *mode = igt_output_get_mode(output);
>> +    igt_display_t *display = &data->display;
>> +    igt_plane_t *plane, *primary = igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY);
>> +    struct igt_fb *ref_fb = &data->fb[2];
>> +    struct igt_fb *clip_fb = &data->fb[3];
>> +    struct igt_fb *clip_fb_xtiled = &data->fb[4];
>> +    struct igt_fb *clip_fb_ytiled = &data->fb[5];
>> +
>> +    prepare_crtc(data, pipe, output);
>> +
>> +    igt_create_color_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
>> +                format, LOCAL_I915_FORMAT_MOD_X_TILED, .5, .5, .5, &data->fb[0]);
>> +
>> +    igt_create_color_fb(display->drm_fd, 256, 256, format,
>> +                LOCAL_I915_FORMAT_MOD_X_TILED, 1., 1., 1., ref_fb);
>> +
>> +    igt_create_fb(display->drm_fd, 80, 128, format,
>> +              LOCAL_DRM_FORMAT_MOD_NONE, clip_fb);
>> +
>> +    igt_create_fb(display->drm_fd, 80, 128, format,
>> +              LOCAL_I915_FORMAT_MOD_X_TILED, clip_fb_xtiled);
> Should \n come after this?
>> +    igt_create_fb(display->drm_fd, 80, 128, format,
>> +              LOCAL_I915_FORMAT_MOD_Y_TILED, clip_fb_ytiled);
>> +
>> +    draw_clip_fb(display, clip_fb);
>> +    draw_clip_fb(display, clip_fb_xtiled);
>> +    draw_clip_fb(display, clip_fb_ytiled);
>> +
>> +    igt_plane_set_fb(primary, &data->fb[0]);
>> +
>> +    for_each_plane_on_pipe(display, pipe, plane) {
>> +        igt_crc_t ref_crc;
>> +
>> +        if (!plane_supports_format(plane, format))
>> +            continue;
>> +
>> +        igt_plane_set_fb(plane, ref_fb);
>> +        igt_plane_set_position(plane, 64, 64);
>> +        igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +        igt_pipe_crc_start(data->pipe_crc);
>> +        igt_pipe_crc_get_single(data->pipe_crc, &ref_crc);
>> +
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb, IGT_ROTATION_0, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_xtiled, IGT_ROTATION_0, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_ytiled, IGT_ROTATION_0, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_ytiled, IGT_ROTATION_90, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb, IGT_ROTATION_180, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_xtiled, IGT_ROTATION_180, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_ytiled, IGT_ROTATION_180, &ref_crc);
>> +        yuv_crop_scale_bug_plane(data, mode, plane, clip_fb_ytiled, IGT_ROTATION_270, &ref_crc);
>> +
>> +        igt_plane_set_fb(plane, plane != primary ? NULL : &data->fb[0]);
>> +        break;
>> +    }
>> +}
>> +
>> +static void yuv_chroma_subpixel_clip_plane_with_cursor(data_t *data,
>> +                            igt_plane_t *plane,
>> +                            struct igt_fb *clip_fb,
>> +                            igt_plane_t *cursor,
>> +                            struct igt_fb *cursor_fb,
>> +                            igt_crc_t *ref_crc,
>> +                            int cursor_x, int cursor_y)
>> +{
>> +    igt_display_t *display = &data->display;
>> +
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    igt_plane_set_position(plane, 64, 64);
>> +    igt_plane_set_rotation(plane, IGT_ROTATION_0);
>> +
>> +    igt_plane_set_fb(cursor, cursor_fb);
>> +    igt_plane_set_position(cursor, cursor_x, cursor_y);
>> +    igt_display_commit2(display, COMMIT_ATOMIC);
>> +
>> +    igt_pipe_crc_drain(data->pipe_crc);
>> +    igt_pipe_crc_get_single(data->pipe_crc, ref_crc);
>> +
>> +    igt_plane_set_fb(cursor, NULL);
>> +}
>> +
>> +static bool yuv_chroma_subpixel_clip_plane_right(data_t *data,
>> +                         igt_rotation_t rotation,
>> +                         igt_plane_t *plane,
>> +                         struct igt_fb *clip_fb,
>> +                         igt_crc_t *ref_crc)
> Should make arguments aligned?
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc = {};
>> +
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    igt_plane_set_position(plane, 64, 64);
>> +    igt_plane_set_rotation(plane, rotation);
>> +    igt_plane_set_size(plane, clip_fb->width - 1, clip_fb->height);
>> +
>> +    switch (rotation) {
>> +    case IGT_ROTATION_180:
>> +        igt_fb_set_position(clip_fb, plane, 1, 0);
>> +    case IGT_ROTATION_0:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width - 1, clip_fb->height);
>> +        break;
>> +
> Extra \n?
>> +    case IGT_ROTATION_270:
>> +        igt_fb_set_position(clip_fb, plane, 0, 1);
>> +    case IGT_ROTATION_90:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width, clip_fb->height - 1);
>> +        break;
>> +    default:
>> +        igt_assert_f(0, "Unhandled rotation %x\n", rotation);
>> +    }
>> +
>> +    if (igt_display_try_commit2(display, COMMIT_ATOMIC) < 0)
>> +        return false;
>> +
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    return true;
>> +}
>> +
>> +static bool yuv_chroma_subpixel_clip_plane_bottom(data_t *data,
>> +                          igt_rotation_t rotation,
>> +                          igt_plane_t *plane,
>> +                          struct igt_fb *clip_fb,
>> +                          igt_crc_t *ref_crc)
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc = {};
>> +
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    igt_plane_set_position(plane, 64, 64);
>> +    igt_plane_set_rotation(plane, rotation);
>> +    igt_plane_set_size(plane, clip_fb->width, clip_fb->height - 1);
>> +
>> +    switch (rotation) {
>> +    case IGT_ROTATION_180:
>> +        igt_fb_set_position(clip_fb, plane, 0, 1);
>> +    case IGT_ROTATION_0:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width, clip_fb->height - 1);
>> +        break;
>> +
> Extra \n?
>> +    case IGT_ROTATION_90:
>> +        igt_fb_set_position(clip_fb, plane, 1, 0);
>> +    case IGT_ROTATION_270:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width - 1, clip_fb->height);
>> +        break;
>> +    default:
>> +        igt_assert_f(0, "Unhandled rotation %x\n", rotation);
>> +    }
>> +
>> +    if (igt_display_try_commit2(display, COMMIT_ATOMIC) < 0)
>> +        return false;
>> +
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    return true;
>> +}
>> +
>> +static bool yuv_chroma_subpixel_clip_plane_left(data_t *data,
>> +                        igt_rotation_t rotation,
>> +                        igt_plane_t *plane,
>> +                        struct igt_fb *clip_fb,
>> +                        igt_crc_t *ref_crc)
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc = {};
>> +
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    igt_plane_set_position(plane, 65, 64);
>> +    igt_plane_set_rotation(plane, rotation);
>> +    igt_plane_set_size(plane, clip_fb->width - 1, clip_fb->height);
>> +
>> +    switch (rotation) {
>> +    case IGT_ROTATION_0:
>> +        igt_fb_set_position(clip_fb, plane, 1, 0);
>> +    case IGT_ROTATION_180:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width - 1, clip_fb->height);
>> +        break;
>> +
> Same here and below clip_plane functions:/ Sorry.
>> +    case IGT_ROTATION_90:
>> +        igt_fb_set_position(clip_fb, plane, 0, 1);
>> +    case IGT_ROTATION_270:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width, clip_fb->height - 1);
>> +        break;
>> +    default:
>> +        igt_assert_f(0, "Unhandled rotation %x\n", rotation);
>> +    }
>> +
>> +    if (igt_display_try_commit2(display, COMMIT_ATOMIC) < 0)
>> +        return false;
>> +
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    return true;
>> +}
>> +
>> +
>> +static bool yuv_chroma_subpixel_clip_plane_top(data_t *data,
>> +                          igt_rotation_t rotation,
>> +                          igt_plane_t *plane,
>> +                          struct igt_fb *clip_fb,
>> +                          igt_crc_t *ref_crc)
>> +{
>> +    igt_display_t *display = &data->display;
>> +    igt_crc_t crc = {};
>> +
>> +    igt_plane_set_fb(plane, clip_fb);
>> +    igt_plane_set_position(plane, 64, 65);
>> +    igt_plane_set_rotation(plane, rotation);
>> +    igt_plane_set_size(plane, clip_fb->width, clip_fb->height - 1);
>> +
>> +    switch (rotation) {
>> +    case IGT_ROTATION_0:
>> +        igt_fb_set_position(clip_fb, plane, 0, 1);
>> +    case IGT_ROTATION_180:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width, clip_fb->height - 1);
>> +        break;
>> +
>> +    case IGT_ROTATION_270:
>> +        igt_fb_set_position(clip_fb, plane, 1, 0);
>> +    case IGT_ROTATION_90:
>> +        igt_fb_set_size(clip_fb, plane, clip_fb->width - 1, clip_fb->height);
>> +        break;
>> +    default:
>> +        igt_assert_f(0, "Unhandled rotation %x\n", rotation);
>> +    }
>> +
>> +    if (igt_display_try_commit2(display, COMMIT_ATOMIC) < 0)
>> +        return false;
>> +
>> +    assert_collected_crc_equal(data->pipe_crc, &crc, ref_crc);
>> +    return true;
>> +}
>> +
>> +static void yuv_chroma_subpixel_clip(data_t *data, enum pipe pipe, igt_output_t *output, unsigned format)
>> +{
>> +    drmModeModeInfo *mode = igt_output_get_mode(output);
>> +    igt_display_t *display = &data->display;
>> +    igt_pipe_t *pipe_obj = &display->pipes[pipe];
>> +    struct igt_fb *bg_fb = &data->fb[0];
>> +    struct igt_fb *bg_cursor_fb = &data->fb[1];
>> +    struct igt_fb *black_cursor_fb = &data->fb[2];
>> +    struct igt_fb *clip_fb = &data->fb[3];
>> +    igt_plane_t *primary = igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_PRIMARY);
>> +    igt_plane_t *cursor = igt_pipe_get_plane_type(pipe_obj, DRM_PLANE_TYPE_CURSOR);
>> +    igt_plane_t *plane;
>> +    cairo_t *cr;
>> +    bool ret = false;
>> +
>> +    prepare_crtc(data, pipe, output);
>> +
>> +    igt_create_color_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
>> +                DRM_FORMAT_XRGB8888, LOCAL_I915_FORMAT_MOD_X_TILED,
>> +                .0, .0, 1., bg_fb);
>> +
>> +    igt_create_color_fb(display->drm_fd, 256, 256,
>> +                    DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
>> +                .0, .0, 1., bg_cursor_fb);
>> +
>> +    igt_create_color_fb(display->drm_fd, 256, 256,
>> +                    DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
>> +                .0, .0, .0, black_cursor_fb);
>> +
>> +    igt_create_fb(display->drm_fd, 256, 256,
>> +              format, LOCAL_I915_FORMAT_MOD_Y_TILED, clip_fb);
>> +
>> +    /* Draw the FB that will be used for clipping the chroma subpixel test. */
>> +    cr = igt_get_cairo_ctx(display->drm_fd, clip_fb);
>> +
>> +    igt_paint_color(cr, 0, 0, clip_fb->width, clip_fb->height, 1., 0., 0.);
>> +    igt_paint_color(cr, 2, 2, clip_fb->width - 4, clip_fb->height - 4, 0., 1., 1.);
>> +    igt_paint_color(cr, 4, 4, clip_fb->width - 8, clip_fb->height - 8, .75, .75, 1.);
>> +
>> +    /* White dots in the corners. */
>> +    igt_paint_color(cr, 0, 0, 6, 6, 1., 1., 1.);
>> +    igt_paint_color(cr, clip_fb->width - 6, 0, 6, 6, 1., 1., 1.);
>> +    igt_paint_color(cr, 0, clip_fb->height - 6, 6, 6, 1., 1., 1.);
>> +    igt_paint_color(cr, clip_fb->width - 6, clip_fb->height - 6, 6, 6, 1., 1., 1.);
>> +
>> +    igt_put_cairo_ctx(display->drm_fd, clip_fb, cr);
>> +
>> +    igt_pipe_crc_start(data->pipe_crc);
>> +
>> +    igt_plane_set_fb(primary, bg_fb);
>> +    for_each_plane_on_pipe(display, pipe, plane) {
>> +        struct igt_fb *cursor_fb = plane == primary ? black_cursor_fb : bg_cursor_fb;
>> +        igt_crc_t ref_crc;
>> +
>> +        if (!plane_supports_format(plane, format) || plane == cursor)
>> +            continue;
>> +
>> +        yuv_chroma_subpixel_clip_plane_with_cursor(data, plane, clip_fb, cursor, cursor_fb, &ref_crc, 63 + clip_fb->width, 64);
>> +        ret |= yuv_chroma_subpixel_clip_plane_right(data, IGT_ROTATION_0, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_right(data, IGT_ROTATION_90, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_right(data, IGT_ROTATION_180, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_right(data, IGT_ROTATION_270, plane, clip_fb, &ref_crc);
>> +
>> +        yuv_chroma_subpixel_clip_plane_with_cursor(data, plane, clip_fb, cursor, cursor_fb, &ref_crc, 64, 63 + clip_fb->height);
>> +        ret |= yuv_chroma_subpixel_clip_plane_bottom(data, IGT_ROTATION_0, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_bottom(data, IGT_ROTATION_90, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_bottom(data, IGT_ROTATION_180, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_bottom(data, IGT_ROTATION_270, plane, clip_fb, &ref_crc);
>> +
>> +        yuv_chroma_subpixel_clip_plane_with_cursor(data, plane, clip_fb, cursor, cursor_fb, &ref_crc, 65 - cursor_fb->width, 64);
>> +        ret |= yuv_chroma_subpixel_clip_plane_left(data, IGT_ROTATION_0, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_left(data, IGT_ROTATION_90, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_left(data, IGT_ROTATION_180, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_left(data, IGT_ROTATION_270, plane, clip_fb, &ref_crc);
>> +
>> +        yuv_chroma_subpixel_clip_plane_with_cursor(data, plane, clip_fb, cursor, cursor_fb, &ref_crc, 64, 65 - cursor_fb->height);
>> +        ret |= yuv_chroma_subpixel_clip_plane_top(data, IGT_ROTATION_0, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_top(data, IGT_ROTATION_90, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_top(data, IGT_ROTATION_180, plane, clip_fb, &ref_crc);
>> +        ret |= yuv_chroma_subpixel_clip_plane_top(data, IGT_ROTATION_270, plane, clip_fb, &ref_crc);
>> +
>> +        /* Reset to defaults */
>> +        igt_plane_set_position(plane, 0, 0);
>> +        igt_plane_set_rotation(plane, IGT_ROTATION_0);
>> +        igt_plane_set_fb(plane, plane == primary ? bg_fb : NULL);
>> +    }
>> +
>> +    igt_require_f(ret, "Could not test subpixel clipping in any corner\n");
>> +}
>> +
>> +static void run_tests_for_pipe(data_t *data, enum pipe pipe,
>> +            const char *fstr, unsigned int format)
> Argument alignment?
>> +{
>> +    igt_output_t *output;
>> +    igt_display_t *display = &data->display;
>> +
>> +    igt_subtest_group {
>> +        igt_fixture {
>> +            igt_display_require_output_on_pipe(display, pipe);
>> +            igt_require(igt_fb_supported_format(format));
>> +            igt_require(pipe_supports_format(display, pipe, format));
>> +        }
>> +
>> +        igt_subtest_f("pipe-%s-%s-rgb-switch",
>> +            kmstest_pipe_name(pipe), fstr)
>> +            for_each_valid_output_on_pipe(display, pipe, output)
>> +                yuv_rgb_switch(data, pipe, output, false, format);
>> +
>> +        igt_subtest_f("pipe-%s-%s-rgb-scaled-switch",
>> +            kmstest_pipe_name(pipe), fstr)
>> +            for_each_valid_output_on_pipe(display, pipe, output)
>> +                yuv_rgb_switch(data, pipe, output, true, format);
>> +
>> +        igt_subtest_f("pipe-%s-%s-valid-width",
>> +            kmstest_pipe_name(pipe), fstr)
>> +            for_each_valid_output_on_pipe(display, pipe, output)
>> +                yuv_valid_width(data, pipe, output, format);
>> +
>> +        igt_subtest_f("pipe-%s-%s-crop-scale-bug",
>> +            kmstest_pipe_name(pipe), fstr)
>> +            for_each_valid_output_on_pipe(display, pipe, output)
>> +                yuv_crop_scale_bug(data, pipe, output, format);
>> +
>> +        igt_subtest_f("pipe-%s-%s-chroma-subpixel-clip",
>> +            kmstest_pipe_name(pipe), fstr)
>> +            for_each_valid_output_on_pipe(display, pipe, output)
>> +                yuv_chroma_subpixel_clip(data, pipe, output, format);
>> +    }
>> +}
>> +
>> +igt_main
>> +{
>> +    data_t data = {};
>> +    enum pipe pipe;
>> +
>> +    igt_skip_on_simulation();
>> +
>> +    igt_fixture {
>> +        data.display.drm_fd = drm_open_driver_master(DRIVER_ANY);
>> +
>> +        kmstest_set_vt_graphics_mode();
>> +        igt_display_require(&data.display, data.display.drm_fd);
>> +        igt_require(data.display.is_atomic);
>> +        igt_require_pipe_crc(data.display.drm_fd);
>> +    }
>> +
>> +    for_each_pipe_static(pipe) {
>> +        run_tests_for_pipe(&data, pipe, "NV12", DRM_FORMAT_NV12);
>> +        run_tests_for_pipe(&data, pipe, "NV16", DRM_FORMAT_NV16);
>> +        run_tests_for_pipe(&data, pipe, "NV21", DRM_FORMAT_NV21);
>> +        run_tests_for_pipe(&data, pipe, "NV61", DRM_FORMAT_NV61);
>> +        run_tests_for_pipe(&data, pipe, "YUV420", DRM_FORMAT_YUV420);
>> +        run_tests_for_pipe(&data, pipe, "YUV422", DRM_FORMAT_YUV422);
>> +        run_tests_for_pipe(&data, pipe, "YVU420", DRM_FORMAT_YVU420);
>> +        run_tests_for_pipe(&data, pipe, "YVU422", DRM_FORMAT_YVU422);
>> +        run_tests_for_pipe(&data, pipe, "P010", DRM_FORMAT_P010);
>> +        run_tests_for_pipe(&data, pipe, "P012", DRM_FORMAT_P012);
>> +        run_tests_for_pipe(&data, pipe, "P016", DRM_FORMAT_P016);
>> +        run_tests_for_pipe(&data, pipe, "YUYV", DRM_FORMAT_YUYV);
>> +        run_tests_for_pipe(&data, pipe, "YVYU", DRM_FORMAT_YVYU);
>> +        run_tests_for_pipe(&data, pipe, "UYVY", DRM_FORMAT_UYVY);
>> +        run_tests_for_pipe(&data, pipe, "VYUY", DRM_FORMAT_VYUY);
>> +        run_tests_for_pipe(&data, pipe, "XYUV8888", DRM_FORMAT_XYUV8888);
> Maarten, I doubt here..so we need to simply add YUV format here and no need to make any other change in kms_yuv igt?

Yes that's the idea. For debugging you can even use XRGB8888, if you're not sure whether the issue is YUV specific.

Most tests are about various corner cases with YUV formats, like upscaling an odd number of pixels which may fail on i915 nv12 for example, because it uses 2x2 pixels.

In those cases it skips, if it doesn't skip we compare unscaled vs scaled, and unclipped (with cursor hiding 1 line/row) vs clipped.

~Maarten

>> +    }
>> +
>> +    igt_fixture {
>> +        igt_display_fini(&data.display);
>> +        close(data.display.drm_fd);
>> +    }
>> +}
>> diff --git a/tests/meson.build b/tests/meson.build
>> index 0f12df26d9fb..b44b5a7c4c4f 100644
>> --- a/tests/meson.build
>> +++ b/tests/meson.build
>> @@ -60,6 +60,7 @@ test_progs = [
>>       'kms_universal_plane',
>>       'kms_vblank',
>>       'kms_vrr',
>> +    'kms_yuv',
>>       'meta_test',
>>       'perf',
>>       'pm_backlight',
>



More information about the igt-dev mailing list