On Fri, Nov 22, 2019 at 07:56:23PM +0200, Ville Syrjala wrote: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > Add selftests for drm_rect. A few basic ones for clipped and unclipped > cases, and a few special ones for specific bugs we had in the code. > > I'm too lazy to think of more corner cases to check at this time. > Maybe later. > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/selftests/Makefile | 3 +- > .../gpu/drm/selftests/drm_modeset_selftests.h | 4 + > .../drm/selftests/test-drm_modeset_common.h | 7 + > drivers/gpu/drm/selftests/test-drm_rect.c | 223 ++++++++++++++++++ > include/drm/drm_rect.h | 2 + > 5 files changed, 238 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c > > diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile > index d2137342b371..0856e4b12f70 100644 > --- a/drivers/gpu/drm/selftests/Makefile > +++ b/drivers/gpu/drm/selftests/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0-only > test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ > test-drm_format.o test-drm_framebuffer.o \ > - test-drm_damage_helper.o test-drm_dp_mst_helper.o > + test-drm_damage_helper.o test-drm_dp_mst_helper.o \ > + test-drm_rect.o > > obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o > diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h > index 1898de0b4a4d..782e285ca383 100644 > --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h > +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h > @@ -6,6 +6,10 @@ > * > * Tests are executed in order by igt/drm_selftests_helper > */ > +selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero) > +selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped) > +selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped) > +selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned) > selftest(check_plane_state, igt_check_plane_state) > selftest(check_drm_format_block_width, igt_check_drm_format_block_width) > selftest(check_drm_format_block_height, igt_check_drm_format_block_height) > diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h > index 0fcb8bbc6a1b..cfb51d8da2bc 100644 > --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h > +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h > @@ -3,6 +3,9 @@ > #ifndef __TEST_DRM_MODESET_COMMON_H__ > #define __TEST_DRM_MODESET_COMMON_H__ > > +#include <linux/errno.h> > +#include <linux/printk.h> > + > #define FAIL(test, msg, ...) \ > do { \ > if (test) { \ > @@ -13,6 +16,10 @@ > > #define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n") > > +int igt_drm_rect_clip_scaled_div_by_zero(void *ignored); > +int igt_drm_rect_clip_scaled_not_clipped(void *ignored); > +int igt_drm_rect_clip_scaled_clipped(void *ignored); > +int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored); > int igt_check_plane_state(void *ignored); > int igt_check_drm_format_block_width(void *ignored); > int igt_check_drm_format_block_height(void *ignored); > diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/selftests/test-drm_rect.c > new file mode 100644 > index 000000000000..3a5ff38321f4 > --- /dev/null > +++ b/drivers/gpu/drm/selftests/test-drm_rect.c > @@ -0,0 +1,223 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Test cases for the drm_rect functions > + */ > + > +#define pr_fmt(fmt) "drm_rect: " fmt > + > +#include <linux/limits.h> > + > +#include <drm/drm_rect.h> > + > +#include "test-drm_modeset_common.h" > + > +int igt_drm_rect_clip_scaled_div_by_zero(void *ignored) > +{ > + struct drm_rect src, dst, clip; > + bool visible; > + > + /* > + * Make sure we don't divide by zero when dst > + * width/height is zero and dst and clip do not intersect. > + */ > + drm_rect_init(&src, 0, 0, 0, 0); > + drm_rect_init(&dst, 0, 0, 0, 0); > + drm_rect_init(&clip, 1, 1, 1, 1); > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + FAIL(visible, "Destination not be visible\n"); ^ "should" missing > + FAIL(drm_rect_visible(&src), "Source should not be visible\n"); > + > + drm_rect_init(&src, 0, 0, 0, 0); > + drm_rect_init(&dst, 3, 3, 0, 0); > + drm_rect_init(&clip, 1, 1, 1, 1); > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + FAIL(visible, "Destination not be visible\n"); ^ "should" missing > + return 0; > +} > + > +int igt_drm_rect_clip_scaled_not_clipped(void *ignored) > +{ > + struct drm_rect src, dst, clip; > + bool visible; > + > + /* 1:1 scaling */ > + drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); > + drm_rect_init(&dst, 0, 0, 1, 1); > + drm_rect_init(&clip, 0, 0, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 1 << 16 || > + src.y1 != 0 || src.y2 != 1 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 1 || > + dst.y1 != 0 || dst.y2 != 1, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 2:1 scaling */ > + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); > + drm_rect_init(&dst, 0, 0, 1, 1); > + drm_rect_init(&clip, 0, 0, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 2 << 16 || > + src.y1 != 0 || src.y2 != 2 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 1 || > + dst.y1 != 0 || dst.y2 != 1, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 1:2 scaling */ > + drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 0, 0, 2, 2); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 1 << 16 || > + src.y1 != 0 || src.y2 != 1 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 2 || > + dst.y1 != 0 || dst.y2 != 2, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); I wonder whether an INT_MAX dst, with src = 0,0,1,1 could be interesting here too. Less practically relevant, it's more about making sure we don't overflow anywhere in silly ways. > + > + return 0; > +} > + > +int igt_drm_rect_clip_scaled_clipped(void *ignored) > +{ > + struct drm_rect src, dst, clip; > + bool visible; > + > + /* 1:1 scaling top/left clip */ > + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 0, 0, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 1 << 16 || > + src.y1 != 0 || src.y2 != 1 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 1 || > + dst.y1 != 0 || dst.y2 != 1, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 1:1 scaling bottom/right clip */ > + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 1, 1, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 || > + src.y1 != 1 << 16 || src.y2 != 2 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 1 || dst.x2 != 2 || > + dst.y1 != 1 || dst.y2 != 2, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 2:1 scaling top/left clip */ > + drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 0, 0, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 2 << 16 || > + src.y1 != 0 || src.y2 != 2 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 1 || > + dst.y1 != 0 || dst.y2 != 1, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 2:1 scaling bottom/right clip */ > + drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 1, 1, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 2 << 16 || src.x2 != 4 << 16 || > + src.y1 != 2 << 16 || src.y2 != 4 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 1 || dst.x2 != 2 || > + dst.y1 != 1 || dst.y2 != 2, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 1:2 scaling top/left clip */ > + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); > + drm_rect_init(&dst, 0, 0, 4, 4); > + drm_rect_init(&clip, 0, 0, 2, 2); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 0 || src.x2 != 1 << 16 || > + src.y1 != 0 || src.y2 != 1 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 0 || dst.x2 != 2 || > + dst.y1 != 0 || dst.y2 != 2, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); > + > + /* 1:2 scaling bottom/right clip */ > + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); > + drm_rect_init(&dst, 0, 0, 4, 4); > + drm_rect_init(&clip, 2, 2, 2, 2); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 || > + src.y1 != 1 << 16 || src.y2 != 2 << 16, > + "Source badly clipped\n"); > + FAIL(dst.x1 != 2 || dst.x2 != 4 || > + dst.y1 != 2 || dst.y2 != 4, > + "Destination badly clipped\n"); > + FAIL(!visible, "Destination should be visible\n"); > + FAIL(!drm_rect_visible(&src), "Source should be visible\n"); Not sure whether dst/src origin != 0,0 would be interesting, but I think this is a solid start. Thanks a lot for typing these. Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> > + > + return 0; > +} > + > +int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored) > +{ > + struct drm_rect src, dst, clip; > + bool visible; > + > + /* > + * 'clip.x2 - dst.x1 >= dst width' could result a negative > + * src rectangle width which is no longer expected by the > + * code as it's using unsigned types. This could lead to > + * the clipped source rectangle appering visible when it > + * should have been fully clipped. Make sure both rectangles > + * end up invisible. > + */ > + drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX); > + drm_rect_init(&dst, 0, 0, 2, 2); > + drm_rect_init(&clip, 3, 3, 1, 1); > + > + visible = drm_rect_clip_scaled(&src, &dst, &clip); > + > + FAIL(visible, "Destination should not be visible\n"); > + FAIL(drm_rect_visible(&src), "Source should not be visible\n"); > + > + return 0; > +} > diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h > index cd0106135b6a..57a3be9e53e4 100644 > --- a/include/drm/drm_rect.h > +++ b/include/drm/drm_rect.h > @@ -24,6 +24,8 @@ > #ifndef DRM_RECT_H > #define DRM_RECT_H > > +#include <linux/types.h> > + > /** > * DOC: rect utils > * > -- > 2.23.0 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx