diff mbox series

[v2,4/4] drm/selftests: Add drm_rect selftests

Message ID 20191122175623.13565-5-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series drm/rect: Bugfixes and selftests | expand

Commit Message

Ville Syrjälä Nov. 22, 2019, 5:56 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

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@linux.intel.com>
---
 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

Comments

Daniel Vetter Nov. 26, 2019, 3:18 p.m. UTC | #1
On Fri, Nov 22, 2019 at 07:56:23PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> 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@linux.intel.com>
> ---
>  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@ffwll.ch>

> +
> +	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@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox series

Patch

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");
+	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");
+	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
+
+	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");
+
+	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");
+
+	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
  *