diff mbox series

[v3,04/18] drm/selftest: Add drm damage helper selftest

Message ID 20181011001657.1715-4-drawat@vmware.com (mailing list archive)
State New, archived
Headers show
Series [v3,01/18] drm: Add a new plane property to send damage during plane update | expand

Commit Message

Deepak Singh Rawat Oct. 11, 2018, 12:16 a.m. UTC
Selftest for drm damage helper iterator functions.

Cc: ville.syrjala@linux.intel.com
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Pekka Paalanen <ppaalanen@gmail.com>
Cc: Daniel Stone <daniel@fooishbar.org>
Cc: intel-gfx@lists.freedesktop.org
Cc: igt-dev@lists.freedesktop.org
Cc: petri.latvala@intel.com
Cc: chris@chris-wilson.co.uk
Signed-off-by: Deepak Rawat <drawat@vmware.com>
---
 drivers/gpu/drm/selftests/Makefile            |   3 +-
 .../selftests/drm_damage_helper_selftests.h   |  22 +
 .../drm/selftests/test-drm_damage_helper.c    | 844 ++++++++++++++++++
 3 files changed, 868 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
 create mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c

Comments

Daniel Vetter Oct. 11, 2018, 4:23 p.m. UTC | #1
On Wed, Oct 10, 2018 at 05:16:43PM -0700, Deepak Rawat wrote:
> Selftest for drm damage helper iterator functions.
> 
> Cc: ville.syrjala@linux.intel.com
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Pekka Paalanen <ppaalanen@gmail.com>
> Cc: Daniel Stone <daniel@fooishbar.org>
> Cc: intel-gfx@lists.freedesktop.org
> Cc: igt-dev@lists.freedesktop.org
> Cc: petri.latvala@intel.com
> Cc: chris@chris-wilson.co.uk
> Signed-off-by: Deepak Rawat <drawat@vmware.com>
> ---
>  drivers/gpu/drm/selftests/Makefile            |   3 +-
>  .../selftests/drm_damage_helper_selftests.h   |  22 +
>  .../drm/selftests/test-drm_damage_helper.c    | 844 ++++++++++++++++++
>  3 files changed, 868 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
>  create mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
> 
> diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
> index 9fc349fa18e9..88ac216f5962 100644
> --- a/drivers/gpu/drm/selftests/Makefile
> +++ b/drivers/gpu/drm/selftests/Makefile
> @@ -1 +1,2 @@
> -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o
> +obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o \
> +				    test-drm_damage_helper.o

With the testcase intagrated into the test-drm-helper.ko module, for
patches 1-4 in this series:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Obviously needs some adjusting on the igt side too, since we seem to be
missing the igt scaffolding for tests-drm-helper.ko.
-Daniel

> diff --git a/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> new file mode 100644
> index 000000000000..3a1cbe05bef0
> --- /dev/null
> +++ b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
> +selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
> +selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
> +selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
> +selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
> +selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
> +selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
> +selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
> +selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
> +selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
> +selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
> +selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
> +selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
> +selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
> +selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
> +selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
> +selftest(damage_iter_damage, igt_damage_iter_damage)
> +selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
> +selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
> +selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
> +selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
> diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> new file mode 100644
> index 000000000000..17754734c47a
> --- /dev/null
> +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> @@ -0,0 +1,844 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Test case for drm_damage_helper functions
> + */
> +
> +#define pr_fmt(fmt) "drm_damage_helper: " fmt
> +
> +#include <linux/module.h>
> +#include <drm/drm_damage_helper.h>
> +
> +#define TESTS "drm_damage_helper_selftests.h"
> +#include "drm_selftest.h"
> +
> +#define FAIL(test, msg, ...) \
> +	do { \
> +		if (test) { \
> +			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
> +			return -EINVAL; \
> +		} \
> +	} while (0)
> +
> +#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
> +
> +static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
> +			  int y2)
> +{
> +	state->src.x1 = x1;
> +	state->src.y1 = y1;
> +	state->src.x2 = x2;
> +	state->src.y2 = y2;
> +}
> +
> +static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
> +			    int y2)
> +{
> +	r->x1 = x1;
> +	r->y1 = y1;
> +	r->x2 = x2;
> +	r->y2 = y2;
> +}
> +
> +static void set_damage_blob(struct drm_property_blob *damage_blob,
> +			    struct drm_mode_rect *r, uint32_t size)
> +{
> +	damage_blob->length = size;
> +	damage_blob->data = r;
> +}
> +
> +static void set_plane_damage(struct drm_plane_state *state,
> +			     struct drm_property_blob *damage_blob)
> +{
> +	state->fb_damage_clips = damage_blob;
> +}
> +
> +static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
> +			      int x1, int y1, int x2, int y2)
> +{
> +	/*
> +	 * Round down x1/y1 and round up x2/y2. This is because damage is not in
> +	 * 16.16 fixed point so to catch all pixels.
> +	 */
> +	int src_x1 = state->src.x1 >> 16;
> +	int src_y1 = state->src.y1 >> 16;
> +	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
> +	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
> +
> +	if (x1 >= x2 || y1 >= y2) {
> +		pr_err("Cannot have damage clip with no dimention.\n");
> +		return false;
> +	}
> +
> +	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
> +		pr_err("Damage cannot be outside rounded plane src.\n");
> +		return false;
> +	}
> +
> +	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
> +		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static int igt_damage_iter_no_damage(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src same as fb size. */
> +	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
> +	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_fractional_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src has fractional part. */
> +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_src_moved(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src moved since old plane state. */
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 10 << 16, 10 << 16,
> +		      (10 + 1024) << 16, (10 + 768) << 16);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src has fractional part and it moved since old plane state. */
> +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_not_visible(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = false,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should have no damage.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_no_crtc(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = 0,
> +		.fb = &fb,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should have no damage.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_no_damage_no_fb(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = 0,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should have no damage.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_simple_damage(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	/* Damage set to plane src */
> +	set_damage_clip(&damage, 0, 0, 1024, 768);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage when set.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	set_damage_clip(&damage, 256, 192, 768, 576);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage when set.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_intersect_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	/* Damage intersect with plane src. */
> +	set_damage_clip(&damage, 256, 192, 1360, 768);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage clipped to src.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_outside_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	/* Damage clip outside plane src */
> +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should have no damage.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_fractional_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src has fractional part. */
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_damage_clip(&damage, 10, 10, 256, 330);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage when set.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src has fractional part. */
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	/* Damage intersect with plane src. */
> +	set_damage_clip(&damage, 10, 1, 1360, 330);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src has fractional part. */
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	/* Damage clip outside plane src */
> +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should have no damage.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_src_moved(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src moved since old plane state. */
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 10 << 16, 10 << 16,
> +		      (10 + 1024) << 16, (10 + 768) << 16);
> +	set_damage_clip(&damage, 20, 30, 256, 256);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage;
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	/* Plane src with fractional part moved since old plane state. */
> +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	/* Damage intersect with plane src. */
> +	set_damage_clip(&damage, 20, 30, 1360, 256);
> +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_damage(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage[2];
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	/* 2 damage clips. */
> +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> +		if (num_hits == 0)
> +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
> +		if (num_hits == 1)
> +			FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
> +		num_hits++;
> +	}
> +
> +	FAIL(num_hits != 2, "Should return damage when set.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_damage_one_intersect(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage[2];
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	/* 2 damage clips, one intersect plane src. */
> +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> +	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
> +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> +		if (num_hits == 0)
> +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
> +		if (num_hits == 1)
> +			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> +		num_hits++;
> +	}
> +
> +	FAIL(num_hits != 2, "Should return damage when set.");
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_damage_one_outside(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage[2];
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> +	/* 2 damage clips, one outside plane src. */
> +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return damage when set.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_damage_src_moved(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage[2];
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = true,
> +	};
> +
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	/* 2 damage clips, one outside plane src. */
> +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 1, "Should return round off plane src as damage.");
> +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> +
> +	return 0;
> +}
> +
> +static int igt_damage_iter_damage_not_visible(void *ignored)
> +{
> +	struct drm_atomic_helper_damage_iter iter;
> +	struct drm_plane_state old_state;
> +	struct drm_property_blob damage_blob;
> +	struct drm_mode_rect damage[2];
> +	struct drm_rect clip;
> +	uint32_t num_hits = 0;
> +
> +	struct drm_framebuffer fb = {
> +		.width = 2048,
> +		.height = 2048
> +	};
> +
> +	struct drm_plane_state state = {
> +		.crtc = ZERO_SIZE_PTR,
> +		.fb = &fb,
> +		.visible = false,
> +	};
> +
> +	set_plane_src(&old_state, 0x40002, 0x40002,
> +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> +	/* 2 damage clips, one outside plane src. */
> +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> +	set_plane_damage(&state, &damage_blob);
> +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> +	drm_atomic_for_each_plane_damage(&iter, &clip)
> +		num_hits++;
> +
> +	FAIL(num_hits != 0, "Should not return any damage.");
> +
> +	return 0;
> +}
> +
> +#include "drm_selftest.c"
> +
> +static int __init test_drm_damage_helper_init(void)
> +{
> +	int err;
> +
> +	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
> +
> +	return err > 0 ? 0 : err;
> +}
> +
> +static void __exit test_drm_damage_helper_exit(void)
> +{
> +}
> +
> +module_init(test_drm_damage_helper_init);
> +module_exit(test_drm_damage_helper_exit);
> +
> +MODULE_AUTHOR("VMware Inc.");
> +MODULE_LICENSE("GPL");
> -- 
> 2.17.1
>
Deepak Singh Rawat Oct. 15, 2018, 4:11 p.m. UTC | #2
> On Wed, Oct 10, 2018 at 05:16:43PM -0700, Deepak Rawat wrote:
> > Selftest for drm damage helper iterator functions.
> >
> > Cc: ville.syrjala@linux.intel.com
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Cc: Pekka Paalanen <ppaalanen@gmail.com>
> > Cc: Daniel Stone <daniel@fooishbar.org>
> > Cc: intel-gfx@lists.freedesktop.org
> > Cc: igt-dev@lists.freedesktop.org
> > Cc: petri.latvala@intel.com
> > Cc: chris@chris-wilson.co.uk
> > Signed-off-by: Deepak Rawat <drawat@vmware.com>
> > ---
> >  drivers/gpu/drm/selftests/Makefile            |   3 +-
> >  .../selftests/drm_damage_helper_selftests.h   |  22 +
> >  .../drm/selftests/test-drm_damage_helper.c    | 844
> ++++++++++++++++++
> >  3 files changed, 868 insertions(+), 1 deletion(-)
> >  create mode 100644
> drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> >  create mode 100644 drivers/gpu/drm/selftests/test-
> drm_damage_helper.c
> >
> > diff --git a/drivers/gpu/drm/selftests/Makefile
> b/drivers/gpu/drm/selftests/Makefile
> > index 9fc349fa18e9..88ac216f5962 100644
> > --- a/drivers/gpu/drm/selftests/Makefile
> > +++ b/drivers/gpu/drm/selftests/Makefile
> > @@ -1 +1,2 @@
> > -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> helper.o
> > +obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> helper.o \
> > +				    test-drm_damage_helper.o
> 
> With the testcase intagrated into the test-drm-helper.ko module, for
> patches 1-4 in this series:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Obviously needs some adjusting on the igt side too, since we seem to be
> missing the igt scaffolding for tests-drm-helper.ko.
> -Daniel

Hi Daniel,

Thanks for the review. I am a little confused here. Should we have single
kernel module for drm plane helper selftest and damage helper selftest?
Also shall I rename the kernel selfttest to kms_*?

For user-space igt test it should be it makes sense to rename to kms_selftets?

> 
> > diff --git a/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > new file mode 100644
> > index 000000000000..3a1cbe05bef0
> > --- /dev/null
> > +++ b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > @@ -0,0 +1,22 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
> > +selftest(damage_iter_no_damage_fractional_src,
> igt_damage_iter_no_damage_fractional_src)
> > +selftest(damage_iter_no_damage_src_moved,
> igt_damage_iter_no_damage_src_moved)
> > +selftest(damage_iter_no_damage_fractional_src_moved,
> igt_damage_iter_no_damage_fractional_src_moved)
> > +selftest(damage_iter_no_damage_not_visible,
> igt_damage_iter_no_damage_not_visible)
> > +selftest(damage_iter_no_damage_no_crtc,
> igt_damage_iter_no_damage_no_crtc)
> > +selftest(damage_iter_no_damage_no_fb,
> igt_damage_iter_no_damage_no_fb)
> > +selftest(damage_iter_simple_damage,
> igt_damage_iter_simple_damage)
> > +selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
> > +selftest(damage_iter_single_damage_intersect_src,
> igt_damage_iter_single_damage_intersect_src)
> > +selftest(damage_iter_single_damage_outside_src,
> igt_damage_iter_single_damage_outside_src)
> > +selftest(damage_iter_single_damage_fractional_src,
> igt_damage_iter_single_damage_fractional_src)
> > +selftest(damage_iter_single_damage_intersect_fractional_src,
> igt_damage_iter_single_damage_intersect_fractional_src)
> > +selftest(damage_iter_single_damage_outside_fractional_src,
> igt_damage_iter_single_damage_outside_fractional_src)
> > +selftest(damage_iter_single_damage_src_moved,
> igt_damage_iter_single_damage_src_moved)
> > +selftest(damage_iter_single_damage_fractional_src_moved,
> igt_damage_iter_single_damage_fractional_src_moved)
> > +selftest(damage_iter_damage, igt_damage_iter_damage)
> > +selftest(damage_iter_damage_one_intersect,
> igt_damage_iter_damage_one_intersect)
> > +selftest(damage_iter_damage_one_outside,
> igt_damage_iter_damage_one_outside)
> > +selftest(damage_iter_damage_src_moved,
> igt_damage_iter_damage_src_moved)
> > +selftest(damage_iter_damage_not_visible,
> igt_damage_iter_damage_not_visible)
> > diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > new file mode 100644
> > index 000000000000..17754734c47a
> > --- /dev/null
> > +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > @@ -0,0 +1,844 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Test case for drm_damage_helper functions
> > + */
> > +
> > +#define pr_fmt(fmt) "drm_damage_helper: " fmt
> > +
> > +#include <linux/module.h>
> > +#include <drm/drm_damage_helper.h>
> > +
> > +#define TESTS "drm_damage_helper_selftests.h"
> > +#include "drm_selftest.h"
> > +
> > +#define FAIL(test, msg, ...) \
> > +	do { \
> > +		if (test) { \
> > +			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__,
> ##__VA_ARGS__); \
> > +			return -EINVAL; \
> > +		} \
> > +	} while (0)
> > +
> > +#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
> > +
> > +static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int
> x2,
> > +			  int y2)
> > +{
> > +	state->src.x1 = x1;
> > +	state->src.y1 = y1;
> > +	state->src.x2 = x2;
> > +	state->src.y2 = y2;
> > +}
> > +
> > +static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int
> x2,
> > +			    int y2)
> > +{
> > +	r->x1 = x1;
> > +	r->y1 = y1;
> > +	r->x2 = x2;
> > +	r->y2 = y2;
> > +}
> > +
> > +static void set_damage_blob(struct drm_property_blob *damage_blob,
> > +			    struct drm_mode_rect *r, uint32_t size)
> > +{
> > +	damage_blob->length = size;
> > +	damage_blob->data = r;
> > +}
> > +
> > +static void set_plane_damage(struct drm_plane_state *state,
> > +			     struct drm_property_blob *damage_blob)
> > +{
> > +	state->fb_damage_clips = damage_blob;
> > +}
> > +
> > +static bool check_damage_clip(struct drm_plane_state *state, struct
> drm_rect *r,
> > +			      int x1, int y1, int x2, int y2)
> > +{
> > +	/*
> > +	 * Round down x1/y1 and round up x2/y2. This is because damage is
> not in
> > +	 * 16.16 fixed point so to catch all pixels.
> > +	 */
> > +	int src_x1 = state->src.x1 >> 16;
> > +	int src_y1 = state->src.y1 >> 16;
> > +	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
> > +	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
> > +
> > +	if (x1 >= x2 || y1 >= y2) {
> > +		pr_err("Cannot have damage clip with no dimention.\n");
> > +		return false;
> > +	}
> > +
> > +	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
> > +		pr_err("Damage cannot be outside rounded plane src.\n");
> > +		return false;
> > +	}
> > +
> > +	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
> > +		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r-
> >y2);
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static int igt_damage_iter_no_damage(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src same as fb size. */
> > +	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
> > +	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_fractional_src(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src has fractional part. */
> > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_src_moved(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src moved since old plane state. */
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_fractional_src_moved(void
> *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src has fractional part and it moved since old plane state. */
> > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_not_visible(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = false,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should have no damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_no_crtc(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = 0,
> > +		.fb = &fb,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should have no damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_no_damage_no_fb(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = 0,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should have no damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_simple_damage(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	/* Damage set to plane src */
> > +	set_damage_clip(&damage, 0, 0, 1024, 768);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage when set.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_damage_clip(&damage, 256, 192, 768, 576);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage when set.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_intersect_src(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	/* Damage intersect with plane src. */
> > +	set_damage_clip(&damage, 256, 192, 1360, 768);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage clipped to src.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_outside_src(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	/* Damage clip outside plane src */
> > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should have no damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_fractional_src(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src has fractional part. */
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_damage_clip(&damage, 10, 10, 256, 330);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage when set.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_intersect_fractional_src(void
> *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src has fractional part. */
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	/* Damage intersect with plane src. */
> > +	set_damage_clip(&damage, 10, 1, 1360, 330);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage clipped to rounded off
> src.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_outside_fractional_src(void
> *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src has fractional part. */
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	/* Damage clip outside plane src */
> > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should have no damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_src_moved(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src moved since old plane state. */
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > +	set_damage_clip(&damage, 20, 30, 256, 256);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_single_damage_fractional_src_moved(void
> *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage;
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	/* Plane src with fractional part moved since old plane state. */
> > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	/* Damage intersect with plane src. */
> > +	set_damage_clip(&damage, 20, 30, 1360, 256);
> > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_damage(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage[2];
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	/* 2 damage clips. */
> > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > +		if (num_hits == 0)
> > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> 200, 180));
> > +		if (num_hits == 1)
> > +			FAIL_ON(!check_damage_clip(&state, &clip, 240,
> 200, 280, 250));
> > +		num_hits++;
> > +	}
> > +
> > +	FAIL(num_hits != 2, "Should return damage when set.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_damage_one_intersect(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage[2];
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	/* 2 damage clips, one intersect plane src. */
> > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > +	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
> > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > +		if (num_hits == 0)
> > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> 200, 180));
> > +		if (num_hits == 1)
> > +			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4,
> 1029, 773));
> > +		num_hits++;
> > +	}
> > +
> > +	FAIL(num_hits != 2, "Should return damage when set.");
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_damage_one_outside(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage[2];
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > +	/* 2 damage clips, one outside plane src. */
> > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return damage when set.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_damage_src_moved(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage[2];
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = true,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	/* 2 damage clips, one outside plane src. */
> > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 1, "Should return round off plane src as damage.");
> > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > +
> > +	return 0;
> > +}
> > +
> > +static int igt_damage_iter_damage_not_visible(void *ignored)
> > +{
> > +	struct drm_atomic_helper_damage_iter iter;
> > +	struct drm_plane_state old_state;
> > +	struct drm_property_blob damage_blob;
> > +	struct drm_mode_rect damage[2];
> > +	struct drm_rect clip;
> > +	uint32_t num_hits = 0;
> > +
> > +	struct drm_framebuffer fb = {
> > +		.width = 2048,
> > +		.height = 2048
> > +	};
> > +
> > +	struct drm_plane_state state = {
> > +		.crtc = ZERO_SIZE_PTR,
> > +		.fb = &fb,
> > +		.visible = false,
> > +	};
> > +
> > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > +	/* 2 damage clips, one outside plane src. */
> > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > +	set_plane_damage(&state, &damage_blob);
> > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > +		num_hits++;
> > +
> > +	FAIL(num_hits != 0, "Should not return any damage.");
> > +
> > +	return 0;
> > +}
> > +
> > +#include "drm_selftest.c"
> > +
> > +static int __init test_drm_damage_helper_init(void)
> > +{
> > +	int err;
> > +
> > +	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
> > +
> > +	return err > 0 ? 0 : err;
> > +}
> > +
> > +static void __exit test_drm_damage_helper_exit(void)
> > +{
> > +}
> > +
> > +module_init(test_drm_damage_helper_init);
> > +module_exit(test_drm_damage_helper_exit);
> > +
> > +MODULE_AUTHOR("VMware Inc.");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.17.1
> >
> 
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ff
> wll.ch&amp;data=02%7C01%7Cdrawat%40vmware.com%7C64e7deb3dc264c
> 6f11a008d62f95d96e%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7
> C636748717979714197&amp;sdata=vCz71L%2BoMpFSGFZifg%2F0bR1CxzReLa
> 7Dy3ss3UKeLrU%3D&amp;reserved=0
Daniel Vetter Oct. 16, 2018, 12:21 p.m. UTC | #3
On Mon, Oct 15, 2018 at 04:11:41PM +0000, Deepak Singh Rawat wrote:
> > On Wed, Oct 10, 2018 at 05:16:43PM -0700, Deepak Rawat wrote:
> > > Selftest for drm damage helper iterator functions.
> > >
> > > Cc: ville.syrjala@linux.intel.com
> > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > Cc: Pekka Paalanen <ppaalanen@gmail.com>
> > > Cc: Daniel Stone <daniel@fooishbar.org>
> > > Cc: intel-gfx@lists.freedesktop.org
> > > Cc: igt-dev@lists.freedesktop.org
> > > Cc: petri.latvala@intel.com
> > > Cc: chris@chris-wilson.co.uk
> > > Signed-off-by: Deepak Rawat <drawat@vmware.com>
> > > ---
> > >  drivers/gpu/drm/selftests/Makefile            |   3 +-
> > >  .../selftests/drm_damage_helper_selftests.h   |  22 +
> > >  .../drm/selftests/test-drm_damage_helper.c    | 844
> > ++++++++++++++++++
> > >  3 files changed, 868 insertions(+), 1 deletion(-)
> > >  create mode 100644
> > drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > >  create mode 100644 drivers/gpu/drm/selftests/test-
> > drm_damage_helper.c
> > >
> > > diff --git a/drivers/gpu/drm/selftests/Makefile
> > b/drivers/gpu/drm/selftests/Makefile
> > > index 9fc349fa18e9..88ac216f5962 100644
> > > --- a/drivers/gpu/drm/selftests/Makefile
> > > +++ b/drivers/gpu/drm/selftests/Makefile
> > > @@ -1 +1,2 @@
> > > -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> > helper.o
> > > +obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> > helper.o \
> > > +				    test-drm_damage_helper.o
> > 
> > With the testcase intagrated into the test-drm-helper.ko module, for
> > patches 1-4 in this series:
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > Obviously needs some adjusting on the igt side too, since we seem to be
> > missing the igt scaffolding for tests-drm-helper.ko.
> > -Daniel
> 
> Hi Daniel,
> 
> Thanks for the review. I am a little confused here. Should we have single
> kernel module for drm plane helper selftest and damage helper selftest?
> Also shall I rename the kernel selfttest to kms_*?
> 
> For user-space igt test it should be it makes sense to rename to kms_selftets?

Since I went back&forth on this way too many times:
- igt should be called kms_selftest. Please work together with igt
  maintainers (Arek and Petri), since we also need to update the CI
  building infrastructure to make sure it updates the list of subtests
  implemented by the kernel.

- Kernel module I'd call test-drm_modeset.ko. That kernel module can then
  include the existing test-drm-helper.c (could probably rename to
  test-drm_plane_helper.c for clarity) and your new damage helper (named
  test-drm_damage_helper.c for consistency).

Does that make sense to everyone?

Thanks, Daniel

> 
> > 
> > > diff --git a/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > new file mode 100644
> > > index 000000000000..3a1cbe05bef0
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > @@ -0,0 +1,22 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
> > > +selftest(damage_iter_no_damage_fractional_src,
> > igt_damage_iter_no_damage_fractional_src)
> > > +selftest(damage_iter_no_damage_src_moved,
> > igt_damage_iter_no_damage_src_moved)
> > > +selftest(damage_iter_no_damage_fractional_src_moved,
> > igt_damage_iter_no_damage_fractional_src_moved)
> > > +selftest(damage_iter_no_damage_not_visible,
> > igt_damage_iter_no_damage_not_visible)
> > > +selftest(damage_iter_no_damage_no_crtc,
> > igt_damage_iter_no_damage_no_crtc)
> > > +selftest(damage_iter_no_damage_no_fb,
> > igt_damage_iter_no_damage_no_fb)
> > > +selftest(damage_iter_simple_damage,
> > igt_damage_iter_simple_damage)
> > > +selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
> > > +selftest(damage_iter_single_damage_intersect_src,
> > igt_damage_iter_single_damage_intersect_src)
> > > +selftest(damage_iter_single_damage_outside_src,
> > igt_damage_iter_single_damage_outside_src)
> > > +selftest(damage_iter_single_damage_fractional_src,
> > igt_damage_iter_single_damage_fractional_src)
> > > +selftest(damage_iter_single_damage_intersect_fractional_src,
> > igt_damage_iter_single_damage_intersect_fractional_src)
> > > +selftest(damage_iter_single_damage_outside_fractional_src,
> > igt_damage_iter_single_damage_outside_fractional_src)
> > > +selftest(damage_iter_single_damage_src_moved,
> > igt_damage_iter_single_damage_src_moved)
> > > +selftest(damage_iter_single_damage_fractional_src_moved,
> > igt_damage_iter_single_damage_fractional_src_moved)
> > > +selftest(damage_iter_damage, igt_damage_iter_damage)
> > > +selftest(damage_iter_damage_one_intersect,
> > igt_damage_iter_damage_one_intersect)
> > > +selftest(damage_iter_damage_one_outside,
> > igt_damage_iter_damage_one_outside)
> > > +selftest(damage_iter_damage_src_moved,
> > igt_damage_iter_damage_src_moved)
> > > +selftest(damage_iter_damage_not_visible,
> > igt_damage_iter_damage_not_visible)
> > > diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > > new file mode 100644
> > > index 000000000000..17754734c47a
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > > @@ -0,0 +1,844 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/*
> > > + * Test case for drm_damage_helper functions
> > > + */
> > > +
> > > +#define pr_fmt(fmt) "drm_damage_helper: " fmt
> > > +
> > > +#include <linux/module.h>
> > > +#include <drm/drm_damage_helper.h>
> > > +
> > > +#define TESTS "drm_damage_helper_selftests.h"
> > > +#include "drm_selftest.h"
> > > +
> > > +#define FAIL(test, msg, ...) \
> > > +	do { \
> > > +		if (test) { \
> > > +			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__,
> > ##__VA_ARGS__); \
> > > +			return -EINVAL; \
> > > +		} \
> > > +	} while (0)
> > > +
> > > +#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
> > > +
> > > +static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int
> > x2,
> > > +			  int y2)
> > > +{
> > > +	state->src.x1 = x1;
> > > +	state->src.y1 = y1;
> > > +	state->src.x2 = x2;
> > > +	state->src.y2 = y2;
> > > +}
> > > +
> > > +static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int
> > x2,
> > > +			    int y2)
> > > +{
> > > +	r->x1 = x1;
> > > +	r->y1 = y1;
> > > +	r->x2 = x2;
> > > +	r->y2 = y2;
> > > +}
> > > +
> > > +static void set_damage_blob(struct drm_property_blob *damage_blob,
> > > +			    struct drm_mode_rect *r, uint32_t size)
> > > +{
> > > +	damage_blob->length = size;
> > > +	damage_blob->data = r;
> > > +}
> > > +
> > > +static void set_plane_damage(struct drm_plane_state *state,
> > > +			     struct drm_property_blob *damage_blob)
> > > +{
> > > +	state->fb_damage_clips = damage_blob;
> > > +}
> > > +
> > > +static bool check_damage_clip(struct drm_plane_state *state, struct
> > drm_rect *r,
> > > +			      int x1, int y1, int x2, int y2)
> > > +{
> > > +	/*
> > > +	 * Round down x1/y1 and round up x2/y2. This is because damage is
> > not in
> > > +	 * 16.16 fixed point so to catch all pixels.
> > > +	 */
> > > +	int src_x1 = state->src.x1 >> 16;
> > > +	int src_y1 = state->src.y1 >> 16;
> > > +	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
> > > +	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
> > > +
> > > +	if (x1 >= x2 || y1 >= y2) {
> > > +		pr_err("Cannot have damage clip with no dimention.\n");
> > > +		return false;
> > > +	}
> > > +
> > > +	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
> > > +		pr_err("Damage cannot be outside rounded plane src.\n");
> > > +		return false;
> > > +	}
> > > +
> > > +	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
> > > +		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r-
> > >y2);
> > > +		return false;
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src same as fb size. */
> > > +	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
> > > +	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_fractional_src(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src has fractional part. */
> > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> > damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_src_moved(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src moved since old plane state. */
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_fractional_src_moved(void
> > *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src has fractional part and it moved since old plane state. */
> > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_not_visible(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = false,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_no_crtc(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = 0,
> > > +		.fb = &fb,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_no_damage_no_fb(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = 0,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_simple_damage(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	/* Damage set to plane src */
> > > +	set_damage_clip(&damage, 0, 0, 1024, 768);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_damage_clip(&damage, 256, 192, 768, 576);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_intersect_src(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	/* Damage intersect with plane src. */
> > > +	set_damage_clip(&damage, 256, 192, 1360, 768);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage clipped to src.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_outside_src(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	/* Damage clip outside plane src */
> > > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_fractional_src(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src has fractional part. */
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_damage_clip(&damage, 10, 10, 256, 330);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_intersect_fractional_src(void
> > *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src has fractional part. */
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	/* Damage intersect with plane src. */
> > > +	set_damage_clip(&damage, 10, 1, 1360, 330);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage clipped to rounded off
> > src.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_outside_fractional_src(void
> > *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src has fractional part. */
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	/* Damage clip outside plane src */
> > > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_src_moved(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src moved since old plane state. */
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > > +	set_damage_clip(&damage, 20, 30, 256, 256);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_single_damage_fractional_src_moved(void
> > *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage;
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	/* Plane src with fractional part moved since old plane state. */
> > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	/* Damage intersect with plane src. */
> > > +	set_damage_clip(&damage, 20, 30, 1360, 256);
> > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> > damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_damage(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage[2];
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	/* 2 damage clips. */
> > > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > > +		if (num_hits == 0)
> > > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> > 200, 180));
> > > +		if (num_hits == 1)
> > > +			FAIL_ON(!check_damage_clip(&state, &clip, 240,
> > 200, 280, 250));
> > > +		num_hits++;
> > > +	}
> > > +
> > > +	FAIL(num_hits != 2, "Should return damage when set.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_damage_one_intersect(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage[2];
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	/* 2 damage clips, one intersect plane src. */
> > > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > > +	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
> > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > > +		if (num_hits == 0)
> > > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> > 200, 180));
> > > +		if (num_hits == 1)
> > > +			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4,
> > 1029, 773));
> > > +		num_hits++;
> > > +	}
> > > +
> > > +	FAIL(num_hits != 2, "Should return damage when set.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_damage_one_outside(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage[2];
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > +	/* 2 damage clips, one outside plane src. */
> > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_damage_src_moved(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage[2];
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = true,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	/* 2 damage clips, one outside plane src. */
> > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 1, "Should return round off plane src as damage.");
> > > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int igt_damage_iter_damage_not_visible(void *ignored)
> > > +{
> > > +	struct drm_atomic_helper_damage_iter iter;
> > > +	struct drm_plane_state old_state;
> > > +	struct drm_property_blob damage_blob;
> > > +	struct drm_mode_rect damage[2];
> > > +	struct drm_rect clip;
> > > +	uint32_t num_hits = 0;
> > > +
> > > +	struct drm_framebuffer fb = {
> > > +		.width = 2048,
> > > +		.height = 2048
> > > +	};
> > > +
> > > +	struct drm_plane_state state = {
> > > +		.crtc = ZERO_SIZE_PTR,
> > > +		.fb = &fb,
> > > +		.visible = false,
> > > +	};
> > > +
> > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > +	/* 2 damage clips, one outside plane src. */
> > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > +	set_plane_damage(&state, &damage_blob);
> > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > +		num_hits++;
> > > +
> > > +	FAIL(num_hits != 0, "Should not return any damage.");
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +#include "drm_selftest.c"
> > > +
> > > +static int __init test_drm_damage_helper_init(void)
> > > +{
> > > +	int err;
> > > +
> > > +	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
> > > +
> > > +	return err > 0 ? 0 : err;
> > > +}
> > > +
> > > +static void __exit test_drm_damage_helper_exit(void)
> > > +{
> > > +}
> > > +
> > > +module_init(test_drm_damage_helper_init);
> > > +module_exit(test_drm_damage_helper_exit);
> > > +
> > > +MODULE_AUTHOR("VMware Inc.");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.17.1
> > >
> > 
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ff
> > wll.ch&amp;data=02%7C01%7Cdrawat%40vmware.com%7C64e7deb3dc264c
> > 6f11a008d62f95d96e%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7
> > C636748717979714197&amp;sdata=vCz71L%2BoMpFSGFZifg%2F0bR1CxzReLa
> > 7Dy3ss3UKeLrU%3D&amp;reserved=0
Alexandru-Cosmin Gheorghe Oct. 16, 2018, 12:52 p.m. UTC | #4
On Tue, Oct 16, 2018 at 02:21:17PM +0200, Daniel Vetter wrote:
> On Mon, Oct 15, 2018 at 04:11:41PM +0000, Deepak Singh Rawat wrote:
> > > On Wed, Oct 10, 2018 at 05:16:43PM -0700, Deepak Rawat wrote:
> > > > Selftest for drm damage helper iterator functions.
> > > >
> > > > Cc: ville.syrjala@linux.intel.com
> > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > Cc: Pekka Paalanen <ppaalanen@gmail.com>
> > > > Cc: Daniel Stone <daniel@fooishbar.org>
> > > > Cc: intel-gfx@lists.freedesktop.org
> > > > Cc: igt-dev@lists.freedesktop.org
> > > > Cc: petri.latvala@intel.com
> > > > Cc: chris@chris-wilson.co.uk
> > > > Signed-off-by: Deepak Rawat <drawat@vmware.com>
> > > > ---
> > > >  drivers/gpu/drm/selftests/Makefile            |   3 +-
> > > >  .../selftests/drm_damage_helper_selftests.h   |  22 +
> > > >  .../drm/selftests/test-drm_damage_helper.c    | 844
> > > ++++++++++++++++++
> > > >  3 files changed, 868 insertions(+), 1 deletion(-)
> > > >  create mode 100644
> > > drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > >  create mode 100644 drivers/gpu/drm/selftests/test-
> > > drm_damage_helper.c
> > > >
> > > > diff --git a/drivers/gpu/drm/selftests/Makefile
> > > b/drivers/gpu/drm/selftests/Makefile
> > > > index 9fc349fa18e9..88ac216f5962 100644
> > > > --- a/drivers/gpu/drm/selftests/Makefile
> > > > +++ b/drivers/gpu/drm/selftests/Makefile
> > > > @@ -1 +1,2 @@
> > > > -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> > > helper.o
> > > > +obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-
> > > helper.o \
> > > > +				    test-drm_damage_helper.o
> > > 
> > > With the testcase intagrated into the test-drm-helper.ko module, for
> > > patches 1-4 in this series:
> > > 
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > 
> > > Obviously needs some adjusting on the igt side too, since we seem to be
> > > missing the igt scaffolding for tests-drm-helper.ko.
> > > -Daniel
> > 
> > Hi Daniel,
> > 
> > Thanks for the review. I am a little confused here. Should we have single
> > kernel module for drm plane helper selftest and damage helper selftest?
> > Also shall I rename the kernel selfttest to kms_*?
> > 
> > For user-space igt test it should be it makes sense to rename to kms_selftets?
> 
> Since I went back&forth on this way too many times:
> - igt should be called kms_selftest. Please work together with igt
>   maintainers (Arek and Petri), since we also need to update the CI
>   building infrastructure to make sure it updates the list of subtests
>   implemented by the kernel.
> 
> - Kernel module I'd call test-drm_modeset.ko. That kernel module can then
>   include the existing test-drm-helper.c (could probably rename to
>   test-drm_plane_helper.c for clarity) and your new damage helper (named
>   test-drm_damage_helper.c for consistency).
> 
> Does that make sense to everyone?

I was trying to add some selftests, as well here [1], with that in
mind, I think it makes sense to have just one module, call it
"test-drm_modeset" or whatever and separate the tests source code base
on whatever core functionality they are testing. 

Besides compiling everything together, probably some stuff will have
to move out of test-drm-helper.c into some common header. For example
this "FAIL/FAIL_ON" macros 

[1] https://lists.freedesktop.org/archives/dri-devel/2018-October/192973.html

> 
> Thanks, Daniel
> 
> > 
> > > 
> > > > diff --git a/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > > new file mode 100644
> > > > index 000000000000..3a1cbe05bef0
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > > @@ -0,0 +1,22 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
> > > > +selftest(damage_iter_no_damage_fractional_src,
> > > igt_damage_iter_no_damage_fractional_src)
> > > > +selftest(damage_iter_no_damage_src_moved,
> > > igt_damage_iter_no_damage_src_moved)
> > > > +selftest(damage_iter_no_damage_fractional_src_moved,
> > > igt_damage_iter_no_damage_fractional_src_moved)
> > > > +selftest(damage_iter_no_damage_not_visible,
> > > igt_damage_iter_no_damage_not_visible)
> > > > +selftest(damage_iter_no_damage_no_crtc,
> > > igt_damage_iter_no_damage_no_crtc)
> > > > +selftest(damage_iter_no_damage_no_fb,
> > > igt_damage_iter_no_damage_no_fb)
> > > > +selftest(damage_iter_simple_damage,
> > > igt_damage_iter_simple_damage)
> > > > +selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
> > > > +selftest(damage_iter_single_damage_intersect_src,
> > > igt_damage_iter_single_damage_intersect_src)
> > > > +selftest(damage_iter_single_damage_outside_src,
> > > igt_damage_iter_single_damage_outside_src)
> > > > +selftest(damage_iter_single_damage_fractional_src,
> > > igt_damage_iter_single_damage_fractional_src)
> > > > +selftest(damage_iter_single_damage_intersect_fractional_src,
> > > igt_damage_iter_single_damage_intersect_fractional_src)
> > > > +selftest(damage_iter_single_damage_outside_fractional_src,
> > > igt_damage_iter_single_damage_outside_fractional_src)
> > > > +selftest(damage_iter_single_damage_src_moved,
> > > igt_damage_iter_single_damage_src_moved)
> > > > +selftest(damage_iter_single_damage_fractional_src_moved,
> > > igt_damage_iter_single_damage_fractional_src_moved)
> > > > +selftest(damage_iter_damage, igt_damage_iter_damage)
> > > > +selftest(damage_iter_damage_one_intersect,
> > > igt_damage_iter_damage_one_intersect)
> > > > +selftest(damage_iter_damage_one_outside,
> > > igt_damage_iter_damage_one_outside)
> > > > +selftest(damage_iter_damage_src_moved,
> > > igt_damage_iter_damage_src_moved)
> > > > +selftest(damage_iter_damage_not_visible,
> > > igt_damage_iter_damage_not_visible)
> > > > diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > > b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > > > new file mode 100644
> > > > index 000000000000..17754734c47a
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
> > > > @@ -0,0 +1,844 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +/*
> > > > + * Test case for drm_damage_helper functions
> > > > + */
> > > > +
> > > > +#define pr_fmt(fmt) "drm_damage_helper: " fmt
> > > > +
> > > > +#include <linux/module.h>
> > > > +#include <drm/drm_damage_helper.h>
> > > > +
> > > > +#define TESTS "drm_damage_helper_selftests.h"
> > > > +#include "drm_selftest.h"
> > > > +
> > > > +#define FAIL(test, msg, ...) \
> > > > +	do { \
> > > > +		if (test) { \
> > > > +			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__,
> > > ##__VA_ARGS__); \
> > > > +			return -EINVAL; \
> > > > +		} \
> > > > +	} while (0)
> > > > +
> > > > +#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
> > > > +
> > > > +static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int
> > > x2,
> > > > +			  int y2)
> > > > +{
> > > > +	state->src.x1 = x1;
> > > > +	state->src.y1 = y1;
> > > > +	state->src.x2 = x2;
> > > > +	state->src.y2 = y2;
> > > > +}
> > > > +
> > > > +static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int
> > > x2,
> > > > +			    int y2)
> > > > +{
> > > > +	r->x1 = x1;
> > > > +	r->y1 = y1;
> > > > +	r->x2 = x2;
> > > > +	r->y2 = y2;
> > > > +}
> > > > +
> > > > +static void set_damage_blob(struct drm_property_blob *damage_blob,
> > > > +			    struct drm_mode_rect *r, uint32_t size)
> > > > +{
> > > > +	damage_blob->length = size;
> > > > +	damage_blob->data = r;
> > > > +}
> > > > +
> > > > +static void set_plane_damage(struct drm_plane_state *state,
> > > > +			     struct drm_property_blob *damage_blob)
> > > > +{
> > > > +	state->fb_damage_clips = damage_blob;
> > > > +}
> > > > +
> > > > +static bool check_damage_clip(struct drm_plane_state *state, struct
> > > drm_rect *r,
> > > > +			      int x1, int y1, int x2, int y2)
> > > > +{
> > > > +	/*
> > > > +	 * Round down x1/y1 and round up x2/y2. This is because damage is
> > > not in
> > > > +	 * 16.16 fixed point so to catch all pixels.
> > > > +	 */
> > > > +	int src_x1 = state->src.x1 >> 16;
> > > > +	int src_y1 = state->src.y1 >> 16;
> > > > +	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
> > > > +	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
> > > > +
> > > > +	if (x1 >= x2 || y1 >= y2) {
> > > > +		pr_err("Cannot have damage clip with no dimention.\n");
> > > > +		return false;
> > > > +	}
> > > > +
> > > > +	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
> > > > +		pr_err("Damage cannot be outside rounded plane src.\n");
> > > > +		return false;
> > > > +	}
> > > > +
> > > > +	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
> > > > +		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r-
> > > >y2);
> > > > +		return false;
> > > > +	}
> > > > +
> > > > +	return true;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src same as fb size. */
> > > > +	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
> > > > +	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_fractional_src(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src has fractional part. */
> > > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> > > damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_src_moved(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src moved since old plane state. */
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > > > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_fractional_src_moved(void
> > > *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src has fractional part and it moved since old plane state. */
> > > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_not_visible(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = false,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_no_crtc(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = 0,
> > > > +		.fb = &fb,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_no_damage_no_fb(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = 0,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_simple_damage(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	/* Damage set to plane src */
> > > > +	set_damage_clip(&damage, 0, 0, 1024, 768);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_damage_clip(&damage, 256, 192, 768, 576);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_intersect_src(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	/* Damage intersect with plane src. */
> > > > +	set_damage_clip(&damage, 256, 192, 1360, 768);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage clipped to src.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_outside_src(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	/* Damage clip outside plane src */
> > > > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_fractional_src(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src has fractional part. */
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_damage_clip(&damage, 10, 10, 256, 330);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_intersect_fractional_src(void
> > > *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src has fractional part. */
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	/* Damage intersect with plane src. */
> > > > +	set_damage_clip(&damage, 10, 1, 1360, 330);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage clipped to rounded off
> > > src.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_outside_fractional_src(void
> > > *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src has fractional part. */
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	/* Damage clip outside plane src */
> > > > +	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should have no damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_src_moved(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src moved since old plane state. */
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 10 << 16, 10 << 16,
> > > > +		      (10 + 1024) << 16, (10 + 768) << 16);
> > > > +	set_damage_clip(&damage, 20, 30, 256, 256);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return plane src as damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_single_damage_fractional_src_moved(void
> > > *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage;
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	/* Plane src with fractional part moved since old plane state. */
> > > > +	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	/* Damage intersect with plane src. */
> > > > +	set_damage_clip(&damage, 20, 30, 1360, 256);
> > > > +	set_damage_blob(&damage_blob, &damage, sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return rounded off plane src as
> > > damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_damage(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage[2];
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	/* 2 damage clips. */
> > > > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > > > +		if (num_hits == 0)
> > > > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> > > 200, 180));
> > > > +		if (num_hits == 1)
> > > > +			FAIL_ON(!check_damage_clip(&state, &clip, 240,
> > > 200, 280, 250));
> > > > +		num_hits++;
> > > > +	}
> > > > +
> > > > +	FAIL(num_hits != 2, "Should return damage when set.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_damage_one_intersect(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage[2];
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	/* 2 damage clips, one intersect plane src. */
> > > > +	set_damage_clip(&damage[0], 20, 30, 200, 180);
> > > > +	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
> > > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip) {
> > > > +		if (num_hits == 0)
> > > > +			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30,
> > > 200, 180));
> > > > +		if (num_hits == 1)
> > > > +			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4,
> > > 1029, 773));
> > > > +		num_hits++;
> > > > +	}
> > > > +
> > > > +	FAIL(num_hits != 2, "Should return damage when set.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_damage_one_outside(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage[2];
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
> > > > +	/* 2 damage clips, one outside plane src. */
> > > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return damage when set.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_damage_src_moved(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage[2];
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = true,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	/* 2 damage clips, one outside plane src. */
> > > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 1, "Should return round off plane src as damage.");
> > > > +	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int igt_damage_iter_damage_not_visible(void *ignored)
> > > > +{
> > > > +	struct drm_atomic_helper_damage_iter iter;
> > > > +	struct drm_plane_state old_state;
> > > > +	struct drm_property_blob damage_blob;
> > > > +	struct drm_mode_rect damage[2];
> > > > +	struct drm_rect clip;
> > > > +	uint32_t num_hits = 0;
> > > > +
> > > > +	struct drm_framebuffer fb = {
> > > > +		.width = 2048,
> > > > +		.height = 2048
> > > > +	};
> > > > +
> > > > +	struct drm_plane_state state = {
> > > > +		.crtc = ZERO_SIZE_PTR,
> > > > +		.fb = &fb,
> > > > +		.visible = false,
> > > > +	};
> > > > +
> > > > +	set_plane_src(&old_state, 0x40002, 0x40002,
> > > > +		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
> > > > +	set_plane_src(&state, 0x3fffe, 0x3fffe,
> > > > +		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
> > > > +	/* 2 damage clips, one outside plane src. */
> > > > +	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
> > > > +	set_damage_clip(&damage[1], 240, 200, 280, 250);
> > > > +	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
> > > > +	set_plane_damage(&state, &damage_blob);
> > > > +	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
> > > > +	drm_atomic_for_each_plane_damage(&iter, &clip)
> > > > +		num_hits++;
> > > > +
> > > > +	FAIL(num_hits != 0, "Should not return any damage.");
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +#include "drm_selftest.c"
> > > > +
> > > > +static int __init test_drm_damage_helper_init(void)
> > > > +{
> > > > +	int err;
> > > > +
> > > > +	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
> > > > +
> > > > +	return err > 0 ? 0 : err;
> > > > +}
> > > > +
> > > > +static void __exit test_drm_damage_helper_exit(void)
> > > > +{
> > > > +}
> > > > +
> > > > +module_init(test_drm_damage_helper_init);
> > > > +module_exit(test_drm_damage_helper_exit);
> > > > +
> > > > +MODULE_AUTHOR("VMware Inc.");
> > > > +MODULE_LICENSE("GPL");
> > > > --
> > > > 2.17.1
> > > >
> > > 
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ff
> > > wll.ch&amp;data=02%7C01%7Cdrawat%40vmware.com%7C64e7deb3dc264c
> > > 6f11a008d62f95d96e%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C1%7C0%7
> > > C636748717979714197&amp;sdata=vCz71L%2BoMpFSGFZifg%2F0bR1CxzReLa
> > > 7Dy3ss3UKeLrU%3D&amp;reserved=0
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Deepak Singh Rawat Oct. 16, 2018, 4 p.m. UTC | #5
> > > Obviously needs some adjusting on the igt side too, since we seem to be
> > > missing the igt scaffolding for tests-drm-helper.ko.
> > > -Daniel
> >
> > Hi Daniel,
> >
> > Thanks for the review. I am a little confused here. Should we have single
> > kernel module for drm plane helper selftest and damage helper selftest?
> > Also shall I rename the kernel selfttest to kms_*?
> >
> > For user-space igt test it should be it makes sense to rename to
> kms_selftets?
> 
> Since I went back&forth on this way too many times:
> - igt should be called kms_selftest. Please work together with igt
>   maintainers (Arek and Petri), since we also need to update the CI
>   building infrastructure to make sure it updates the list of subtests
>   implemented by the kernel.
> 
> - Kernel module I'd call test-drm_modeset.ko. That kernel module can then
>   include the existing test-drm-helper.c (could probably rename to
>   test-drm_plane_helper.c for clarity) and your new damage helper (named
>   test-drm_damage_helper.c for consistency).
> 
> Does that make sense to everyone?
> 

Yes it makes sense to me and in fact I had similar changes in mind. And, 
since existing plane selftest are not invoked from igt it's safe to rename
kernel module.
Deepak Singh Rawat Oct. 16, 2018, 4:14 p.m. UTC | #6
> 
> On Tue, Oct 16, 2018 at 02:21:17PM +0200, Daniel Vetter wrote:
> > On Mon, Oct 15, 2018 at 04:11:41PM +0000, Deepak Singh Rawat wrote:
> > > > On Wed, Oct 10, 2018 at 05:16:43PM -0700, Deepak Rawat wrote:
> > > > > Selftest for drm damage helper iterator functions.
> > > > >
> > > > > Cc: ville.syrjala@linux.intel.com
> > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > Cc: Pekka Paalanen <ppaalanen@gmail.com>
> > > > > Cc: Daniel Stone <daniel@fooishbar.org>
> > > > > Cc: intel-gfx@lists.freedesktop.org
> > > > > Cc: igt-dev@lists.freedesktop.org
> > > > > Cc: petri.latvala@intel.com
> > > > > Cc: chris@chris-wilson.co.uk
> > > > > Signed-off-by: Deepak Rawat <drawat@vmware.com>
> > > > > ---
> > > > >  drivers/gpu/drm/selftests/Makefile            |   3 +-
> > > > >  .../selftests/drm_damage_helper_selftests.h   |  22 +
> > > > >  .../drm/selftests/test-drm_damage_helper.c    | 844
> > > > ++++++++++++++++++
> > > > >  3 files changed, 868 insertions(+), 1 deletion(-)
> > > > >  create mode 100644
> > > > drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
> > > > >  create mode 100644 drivers/gpu/drm/selftests/test-
> > > > drm_damage_helper.c
> > > > >
> > > > > diff --git a/drivers/gpu/drm/selftests/Makefile
> > > > b/drivers/gpu/drm/selftests/Makefile
> > > > > index 9fc349fa18e9..88ac216f5962 100644
> > > > > --- a/drivers/gpu/drm/selftests/Makefile
> > > > > +++ b/drivers/gpu/drm/selftests/Makefile
> > > > > @@ -1 +1,2 @@
> > > > > -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-
> drm-
> > > > helper.o
> > > > > +obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-
> drm-
> > > > helper.o \
> > > > > +				    test-drm_damage_helper.o
> > > >
> > > > With the testcase intagrated into the test-drm-helper.ko module, for
> > > > patches 1-4 in this series:
> > > >
> > > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > >
> > > > Obviously needs some adjusting on the igt side too, since we seem to
> be
> > > > missing the igt scaffolding for tests-drm-helper.ko.
> > > > -Daniel
> > >
> > > Hi Daniel,
> > >
> > > Thanks for the review. I am a little confused here. Should we have single
> > > kernel module for drm plane helper selftest and damage helper selftest?
> > > Also shall I rename the kernel selfttest to kms_*?
> > >
> > > For user-space igt test it should be it makes sense to rename to
> kms_selftets?
> >
> > Since I went back&forth on this way too many times:
> > - igt should be called kms_selftest. Please work together with igt
> >   maintainers (Arek and Petri), since we also need to update the CI
> >   building infrastructure to make sure it updates the list of subtests
> >   implemented by the kernel.
> >
> > - Kernel module I'd call test-drm_modeset.ko. That kernel module can then
> >   include the existing test-drm-helper.c (could probably rename to
> >   test-drm_plane_helper.c for clarity) and your new damage helper (named
> >   test-drm_damage_helper.c for consistency).
> >
> > Does that make sense to everyone?
> 
> I was trying to add some selftests, as well here [1], with that in
> mind, I think it makes sense to have just one module, call it
> "test-drm_modeset" or whatever and separate the tests source code base
> on whatever core functionality they are testing.
> 
> Besides compiling everything together, probably some stuff will have
> to move out of test-drm-helper.c into some common header. For example
> this "FAIL/FAIL_ON" macros
> 

Hi,

Thanks for your input. I have similar change in mind after suggestion from
Daniel. Below is initial draft I did yesterday, will move common code to
a common header.

I hope this aligns with what you are doing.

---
 drivers/gpu/drm/selftests/Makefile            |  4 ++-
 .../gpu/drm/selftests/drm_helper_selftests.c  | 27 +++++++++++++++++++
 .../gpu/drm/selftests/drm_helper_selftests.h  | 15 +++++------
 ...-helper.c => drm_plane_helper_selftests.c} | 16 ++++-------
 .../selftests/drm_plane_helper_selftests.h    |  9 +++++++
 5 files changed, 51 insertions(+), 20 deletions(-)
 create mode 100644 drivers/gpu/drm/selftests/drm_helper_selftests.c
 rename drivers/gpu/drm/selftests/{test-drm-helper.c => drm_plane_helper_selftests.c} (96%)
 create mode 100644 drivers/gpu/drm/selftests/drm_plane_helper_selftests.h

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 9fc349fa18e9..560117d64658 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o
+test-drm_helper-y := drm_helper_selftests.o drm_plane_helper_selftests.o
+
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_helper_selftests.c b/drivers/gpu/drm/selftests/drm_helper_selftests.c
new file mode 100644
index 000000000000..873db462fa35
--- /dev/null
+++ b/drivers/gpu/drm/selftests/drm_helper_selftests.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_kms_helper functions
+ */
+
+#include <linux/module.h>
+
+#include "drm_helper_selftests.h"
+
+static int __init test_drm_helper_init(void)
+{
+	int err;
+
+	err = drm_run_plane_helper_selftests();
+
+	return err;
+}
+
+static void __exit test_drm_helper_exit(void)
+{
+}
+
+module_init(test_drm_helper_init);
+module_exit(test_drm_helper_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/drm_helper_selftests.h b/drivers/gpu/drm/selftests/drm_helper_selftests.h
index 9771290ed228..82d076a20bb3 100644
--- a/drivers/gpu/drm/selftests/drm_helper_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_helper_selftests.h
@@ -1,9 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_selftests_helper
- */
-selftest(check_plane_state, igt_check_plane_state)
+
+#ifndef __TEST_DRM_HELPER_H__
+#define __TEST_DRM_HELPER_H__
+
+int drm_run_plane_helper_selftests(void);
+
+#endif
diff --git a/drivers/gpu/drm/selftests/test-drm-helper.c b/drivers/gpu/drm/selftests/drm_plane_helper_selftests.c
similarity index 96%
rename from drivers/gpu/drm/selftests/test-drm-helper.c
rename to drivers/gpu/drm/selftests/drm_plane_helper_selftests.c
index a015712b43e8..11941c14a791 100644
--- a/drivers/gpu/drm/selftests/test-drm-helper.c
+++ b/drivers/gpu/drm/selftests/drm_plane_helper_selftests.c
@@ -1,16 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Test cases for the drm_kms_helper functions
+ * Test cases for the drm_plane_helper functions
  */
 
-#define pr_fmt(fmt) "drm_kms_helper: " fmt
-
-#include <linux/module.h>
+#define pr_fmt(fmt) "drm_plane_helper: " fmt
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_modes.h>
 
-#define TESTS "drm_helper_selftests.h"
+#define TESTS "drm_plane_helper_selftests.h"
 #include "drm_selftest.h"
 
 #define FAIL(test, msg, ...) \
@@ -232,7 +231,7 @@ static int igt_check_plane_state(void *ignored)
 
 #include "drm_selftest.c"
 
-static int __init test_drm_helper_init(void)
+int drm_run_plane_helper_selftests(void)
 {
 	int err;
 
@@ -240,8 +239,3 @@ static int __init test_drm_helper_init(void)
 
 	return err > 0 ? 0 : err;
 }
-
-module_init(test_drm_helper_init);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/drm_plane_helper_selftests.h b/drivers/gpu/drm/selftests/drm_plane_helper_selftests.h
new file mode 100644
index 000000000000..9771290ed228
--- /dev/null
+++ b/drivers/gpu/drm/selftests/drm_plane_helper_selftests.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* List each unit test as selftest(name, function)
+ *
+ * The name is used as both an enum and expanded as igt__name to create
+ * a module parameter. It must be unique and legal for a C identifier.
+ *
+ * Tests are executed in order by igt/drm_selftests_helper
+ */
+selftest(check_plane_state, igt_check_plane_state)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 9fc349fa18e9..88ac216f5962 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1 +1,2 @@ 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o \
+				    test-drm_damage_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
new file mode 100644
index 000000000000..3a1cbe05bef0
--- /dev/null
+++ b/drivers/gpu/drm/selftests/drm_damage_helper_selftests.h
@@ -0,0 +1,22 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
+selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
+selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
+selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
+selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
+selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
+selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
+selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
+selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
+selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
+selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
+selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
+selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
+selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
+selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
+selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
+selftest(damage_iter_damage, igt_damage_iter_damage)
+selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
+selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
+selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
+selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
new file mode 100644
index 000000000000..17754734c47a
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
@@ -0,0 +1,844 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Test case for drm_damage_helper functions
+ */
+
+#define pr_fmt(fmt) "drm_damage_helper: " fmt
+
+#include <linux/module.h>
+#include <drm/drm_damage_helper.h>
+
+#define TESTS "drm_damage_helper_selftests.h"
+#include "drm_selftest.h"
+
+#define FAIL(test, msg, ...) \
+	do { \
+		if (test) { \
+			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+
+static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
+			  int y2)
+{
+	state->src.x1 = x1;
+	state->src.y1 = y1;
+	state->src.x2 = x2;
+	state->src.y2 = y2;
+}
+
+static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
+			    int y2)
+{
+	r->x1 = x1;
+	r->y1 = y1;
+	r->x2 = x2;
+	r->y2 = y2;
+}
+
+static void set_damage_blob(struct drm_property_blob *damage_blob,
+			    struct drm_mode_rect *r, uint32_t size)
+{
+	damage_blob->length = size;
+	damage_blob->data = r;
+}
+
+static void set_plane_damage(struct drm_plane_state *state,
+			     struct drm_property_blob *damage_blob)
+{
+	state->fb_damage_clips = damage_blob;
+}
+
+static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
+			      int x1, int y1, int x2, int y2)
+{
+	/*
+	 * Round down x1/y1 and round up x2/y2. This is because damage is not in
+	 * 16.16 fixed point so to catch all pixels.
+	 */
+	int src_x1 = state->src.x1 >> 16;
+	int src_y1 = state->src.y1 >> 16;
+	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
+	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
+
+	if (x1 >= x2 || y1 >= y2) {
+		pr_err("Cannot have damage clip with no dimention.\n");
+		return false;
+	}
+
+	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
+		pr_err("Damage cannot be outside rounded plane src.\n");
+		return false;
+	}
+
+	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
+		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
+		return false;
+	}
+
+	return true;
+}
+
+static int igt_damage_iter_no_damage(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src same as fb size. */
+	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
+	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_fractional_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src has fractional part. */
+	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	set_plane_src(&state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_src_moved(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src moved since old plane state. */
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 10 << 16, 10 << 16,
+		      (10 + 1024) << 16, (10 + 768) << 16);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src has fractional part and it moved since old plane state. */
+	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_not_visible(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = false,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should have no damage.");
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_no_crtc(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = 0,
+		.fb = &fb,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should have no damage.");
+
+	return 0;
+}
+
+static int igt_damage_iter_no_damage_no_fb(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = 0,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should have no damage.");
+
+	return 0;
+}
+
+static int igt_damage_iter_simple_damage(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	/* Damage set to plane src */
+	set_damage_clip(&damage, 0, 0, 1024, 768);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage when set.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_damage_clip(&damage, 256, 192, 768, 576);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage when set.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_intersect_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	/* Damage intersect with plane src. */
+	set_damage_clip(&damage, 256, 192, 1360, 768);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage clipped to src.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_outside_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	/* Damage clip outside plane src */
+	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should have no damage.");
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_fractional_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src has fractional part. */
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_damage_clip(&damage, 10, 10, 256, 330);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage when set.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src has fractional part. */
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	/* Damage intersect with plane src. */
+	set_damage_clip(&damage, 10, 1, 1360, 330);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src has fractional part. */
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	/* Damage clip outside plane src */
+	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should have no damage.");
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_src_moved(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src moved since old plane state. */
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 10 << 16, 10 << 16,
+		      (10 + 1024) << 16, (10 + 768) << 16);
+	set_damage_clip(&damage, 20, 30, 256, 256);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
+
+	return 0;
+}
+
+static int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage;
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	/* Plane src with fractional part moved since old plane state. */
+	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	/* Damage intersect with plane src. */
+	set_damage_clip(&damage, 20, 30, 1360, 256);
+	set_damage_blob(&damage_blob, &damage, sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+
+	return 0;
+}
+
+static int igt_damage_iter_damage(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	/* 2 damage clips. */
+	set_damage_clip(&damage[0], 20, 30, 200, 180);
+	set_damage_clip(&damage[1], 240, 200, 280, 250);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip) {
+		if (num_hits == 0)
+			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+		if (num_hits == 1)
+			FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+		num_hits++;
+	}
+
+	FAIL(num_hits != 2, "Should return damage when set.");
+
+	return 0;
+}
+
+static int igt_damage_iter_damage_one_intersect(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	/* 2 damage clips, one intersect plane src. */
+	set_damage_clip(&damage[0], 20, 30, 200, 180);
+	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip) {
+		if (num_hits == 0)
+			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+		if (num_hits == 1)
+			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+		num_hits++;
+	}
+
+	FAIL(num_hits != 2, "Should return damage when set.");
+
+	return 0;
+}
+
+static int igt_damage_iter_damage_one_outside(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	/* 2 damage clips, one outside plane src. */
+	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+	set_damage_clip(&damage[1], 240, 200, 280, 250);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return damage when set.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+
+	return 0;
+}
+
+static int igt_damage_iter_damage_src_moved(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = true,
+	};
+
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	/* 2 damage clips, one outside plane src. */
+	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+	set_damage_clip(&damage[1], 240, 200, 280, 250);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 1, "Should return round off plane src as damage.");
+	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
+
+	return 0;
+}
+
+static int igt_damage_iter_damage_not_visible(void *ignored)
+{
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_plane_state old_state;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	uint32_t num_hits = 0;
+
+	struct drm_framebuffer fb = {
+		.width = 2048,
+		.height = 2048
+	};
+
+	struct drm_plane_state state = {
+		.crtc = ZERO_SIZE_PTR,
+		.fb = &fb,
+		.visible = false,
+	};
+
+	set_plane_src(&old_state, 0x40002, 0x40002,
+		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
+	set_plane_src(&state, 0x3fffe, 0x3fffe,
+		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
+	/* 2 damage clips, one outside plane src. */
+	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
+	set_damage_clip(&damage[1], 240, 200, 280, 250);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_for_each_plane_damage(&iter, &clip)
+		num_hits++;
+
+	FAIL(num_hits != 0, "Should not return any damage.");
+
+	return 0;
+}
+
+#include "drm_selftest.c"
+
+static int __init test_drm_damage_helper_init(void)
+{
+	int err;
+
+	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+
+	return err > 0 ? 0 : err;
+}
+
+static void __exit test_drm_damage_helper_exit(void)
+{
+}
+
+module_init(test_drm_damage_helper_init);
+module_exit(test_drm_damage_helper_exit);
+
+MODULE_AUTHOR("VMware Inc.");
+MODULE_LICENSE("GPL");