[PATCH i-g-t v6 1/1] tests/intel/kms_dirty_fbc: Add kms_dirty_fbc test for DIRTYFB ioctl with fbc

Sharma, Swati2 swati2.sharma at intel.com
Mon Jan 27 11:51:30 UTC 2025


Hi Santosh,

Please add commit message. PFB review comments.

On 24-01-2025 05:33 pm, Santhosh Reddy Guddati wrote:
> v2: Fix typo , add version check for feature support,
>      extend support for all pipes (Rama Naidu).
>
> v3: Add new subtest to scatter dirty rectangles at differnt places in a
>      frame and commit all rectangles at once (Rama Naidu).
>      Add a negative case with invalid coordinates (Vinod)
>
> v4: Add subtest `fbc-dirty-rectangle-basic` to perform sanity checks
>      by sending multiple damaged areas with non-PSR modes.(Vinod)
>      Update `meson.build` to include the new test.
>
> v5: Include checks to ensure FBC is enabled during tests.(Vinod)
>      Add dynamic subtests for fbc-dirty-rectangle-different-formats
>      and fbc-dirty-rectangle-dirtyfb-ioctl. (Vinod)
>
> v6: Update meson.build to include kms_fbc_dirty_rect.
>
> Signed-off-by: Santhosh Reddy Guddati <santhosh.reddy.guddati at intel.com>
> ---
>   tests/intel/kms_fbc_dirty_rect.c | 348 +++++++++++++++++++++++++++++++
>   tests/meson.build                |   1 +
>   2 files changed, 349 insertions(+)
>   create mode 100644 tests/intel/kms_fbc_dirty_rect.c
>
> diff --git a/tests/intel/kms_fbc_dirty_rect.c b/tests/intel/kms_fbc_dirty_rect.c
> new file mode 100644
> index 000000000..b05367011
> --- /dev/null
> +++ b/tests/intel/kms_fbc_dirty_rect.c
> @@ -0,0 +1,348 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +
> +/**
> + * TEST: kms dirty fbc
> + * Category: Display
> + * Description: Test DIRTYFB ioctl functionality with FBC enabled.
> + * Driver requirement: i915, xe
Since this test is applicable for display ver >= 30; remove i915
> + * Functionality: dirtyfb, fbc
> + * Mega feature: General Display Features
> + * Test category: functionality test
> + */
> +
> +#include "igt.h"
> +#include "i915/intel_fbc.h"
> +
> +enum operations {
> +	FRONTBUFFER,
> +};
> +
> +/**
> + * SUBTEST: fbc-dirty-rectangle-basic
> + * Description: Sanity test to verify FBC DR by sending multiple damaged areas with non psr modes
> + * Functionality: fbc
Since fbc is already added above, remove from here. Same implies to 
other subtests.
> + *
> + * SUBTEST: fbc-dirty-rectangle-different-formats
> + * Description: Sanity test to verify FBC DR by sending multiple
> + *              damaged areas with different formats.
> + * Functionality: fbc
> + *
> + * SUBTEST: fbc-dirty-rectangle-dirtyfb-ioctl
> + * Description: Sanity test to verify FBC DR by sending
> + *              multiple damaged areas with dirtyfb ioctl with fbc enabled.
> + * Functionality: fbc
> + */
> +
> +#define SQUARE_SIZE 100
> +#define SQUARE_OFFSET 100
> +#define SQUARE_OFFSET_2 600
> +
> +typedef struct {
> +	int drm_fd;
> +	int debugfs_fd;
> +	igt_display_t display;
> +	drmModeModeInfo *mode;
> +	igt_output_t *output;
> +	igt_pipe_crc_t *pipe_crc;
> +	enum pipe pipe;
> +	enum operations op;
> +	u32 format;
> +
> +	igt_crc_t ref_crc;
> +
> +	enum {
> +		FEATURE_NONE  = 0,
> +		FEATURE_PSR   = 1,
> +		FEATURE_FBC   = 2,
> +		FEATURE_DRRS  = 4,
> +		FEATURE_COUNT = 8,
> +		FEATURE_DEFAULT = 8,
> +	} feature;
> +} data_t;
> +
> +
> +static void set_damage_clip(struct drm_mode_rect *damage, int x1, int y1, int x2, int y2)
> +{
> +	damage->x1 = x1;
> +	damage->y1 = y1;
> +	damage->x2 = x2;
> +	damage->y2 = y2;
> +}
> +
> +static void dirty_rect_create_fb(data_t *data, struct igt_fb *fb, int nrects,
> +				 struct drm_mode_rect *rect)
> +{
> +	cairo_t *cr;
> +
> +	igt_create_color_fb(data->drm_fd, data->mode->hdisplay, data->mode->vdisplay,
> +			    DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR,
> +			    0.0, 0.0, 1.0, fb);
> +
> +	if (!nrects || !rect)
> +		return;
> +
> +	cr = igt_get_cairo_ctx(data->drm_fd, fb);
> +
> +	for (int i = 0; i < nrects; i++) {
> +		igt_paint_color_alpha(cr, rect[i].x1, rect[i].y1,
> +				      rect[i].x2 - rect[i].x1,
> +				      rect[i].y2 - rect[i].y1,
> +				      1.0, 1.0, 1.0, 1.0);
> +	}
> +	igt_put_cairo_ctx(cr);
> +}
> +
> +static void fbc_dirty_rectangle_complete_set(data_t *data)
> +{
> +	igt_pipe_crc_t *pipe_crc = data->pipe_crc;
> +	igt_display_t *display = &data->display;
> +	igt_output_t *output = data->output;
> +	igt_plane_t *primary;
> +	drmModeModeInfo *mode;
> +	struct igt_fb main_fb;
> +	struct igt_fb rect_1_fb;
> +	struct igt_fb rect_2_fb;
> +	struct igt_fb rect_combined_fb;
> +	struct drm_mode_rect rect1;
> +	struct drm_mode_rect rect2;
> +	struct drm_mode_rect rect_combined[2];
> +	struct drm_mode_rect full_rect;
> +	igt_crc_t main_fb_crc, rect_1_fb_crc, rect_2_fb_crc, rect_combined_fb_crc, crc;
> +	int ret;
> +
> +	mode = igt_output_get_mode(output);
> +	igt_output_set_pipe(output, data->pipe);
> +	if (!pipe_crc) {
> +		pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
> +					    IGT_PIPE_CRC_SOURCE_AUTO);
> +		igt_assert(pipe_crc);
> +	}
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +
> +	set_damage_clip(&full_rect, 0, 0, mode->hdisplay-1, mode->vdisplay-1);
> +	set_damage_clip(&rect1, SQUARE_OFFSET, SQUARE_OFFSET,
> +			SQUARE_OFFSET + SQUARE_SIZE, SQUARE_OFFSET + SQUARE_SIZE);
> +	set_damage_clip(&rect2, SQUARE_OFFSET_2, SQUARE_OFFSET_2,
> +			SQUARE_OFFSET_2 + SQUARE_SIZE, SQUARE_OFFSET_2 + SQUARE_SIZE);
> +	set_damage_clip(&rect_combined[0], rect1.x1, rect1.y1, rect1.x2, rect1.y2);
> +	set_damage_clip(&rect_combined[1], rect2.x1, rect2.y1, rect2.x2, rect2.y2);
> +
> +	dirty_rect_create_fb(data, &main_fb, 0, NULL);
> +	dirty_rect_create_fb(data, &rect_1_fb, 1, &rect1);
> +	dirty_rect_create_fb(data, &rect_2_fb, 1, &rect2);
> +	dirty_rect_create_fb(data, &rect_combined_fb, 2, rect_combined);
> +
> +	/* main_fb blank blue screen - get and store crc*/
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	dirty_rect_create_fb(data, &main_fb, 0, NULL);
> +	dirty_rect_create_fb(data, &rect_1_fb, 1, &rect1);
> +	dirty_rect_create_fb(data, &rect_2_fb, 1, &rect2);
> +	dirty_rect_create_fb(data, &rect_combined_fb, 2, rect_combined);
> +
> +	/* main_fb blank blue screen - get and store crc*/
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	igt_plane_set_fb(primary, &main_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &main_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Whole blue screen with one white rect and collect crc */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	igt_plane_set_fb(primary, &rect_1_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &rect_1_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Second white rect and collect crc */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	igt_plane_set_fb(primary, &rect_2_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &rect_2_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Both rects and collect crc */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	igt_plane_set_fb(primary, &rect_combined_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &rect_combined_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Put full blank screen back */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &full_rect, sizeof(full_rect));
> +	igt_plane_set_fb(primary, &main_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &crc);
> +	igt_assert_crc_equal(&crc, &main_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Set combined rect - draw two white rects using damage area*/
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &rect_combined, sizeof(rect_combined));
> +	igt_plane_set_fb(primary, &rect_combined_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &crc);
> +	igt_assert_crc_equal(&crc, &rect_combined_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Clear first rect using damage area. Only the second rect should be visible here! */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &rect1, sizeof(rect1));
> +	igt_plane_set_fb(primary, &main_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &crc);
> +	igt_assert_crc_equal(&crc, &rect_2_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	/* Clear the second rect as well. Now back to original blank screen */
> +	igt_plane_replace_prop_blob(primary, IGT_PLANE_FB_DAMAGE_CLIPS,
> +				    &rect2, sizeof(rect2));
> +	igt_plane_set_fb(primary, &main_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_pipe_crc_collect_crc(pipe_crc, &crc);
> +	igt_assert_crc_equal(&crc, &main_fb_crc);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	igt_plane_set_fb(primary, NULL);
> +	igt_remove_fb(data->drm_fd, &main_fb);
> +	igt_remove_fb(data->drm_fd, &rect_1_fb);
> +	igt_remove_fb(data->drm_fd, &rect_2_fb);
> +	igt_remove_fb(data->drm_fd, &rect_combined_fb);
> +	igt_display_commit2(display, COMMIT_ATOMIC);
> +	igt_assert_f(intel_fbc_is_enabled(data->drm_fd, data->pipe,
> +					  IGT_LOG_WARN), "FBC is not enabled\n");
> +
> +	if (data->op == FRONTBUFFER) {
> +		drmModeClip clip;
> +		struct igt_fb fb;
> +
> +		clip.x1 = clip.y1 = SQUARE_OFFSET;
> +		clip.x2 = clip.y2 = SQUARE_OFFSET + SQUARE_SIZE;
> +
> +		dirty_rect_create_fb(data, &fb, 1, (struct drm_mode_rect *)&clip);
> +		ret = drmModeDirtyFB(data->drm_fd, fb.fb_id, &clip, 1);
> +		igt_assert(ret == 0);
> +	}
> +}
> +
> +static void prepare_test(data_t *data, igt_output_t *output)
> +{
> +	bool is_fbc_supported = false;
> +
> +	is_fbc_supported = intel_fbc_supported_on_chipset(data->drm_fd, data->pipe);
> +
> +	igt_require_f(is_fbc_supported, "FBC not supported on this platform\n");
> +
> +	if (data->feature & FEATURE_FBC)
> +		intel_fbc_enable(data->drm_fd);
> +
> +}
> +
> +static void fbc_dirty_rectangle_basic(data_t *data)
> +{
> +	prepare_test(data, NULL);
> +	return fbc_dirty_rectangle_complete_set(data);
> +}
> +
> +igt_main
> +{
> +	data_t data = {0};
> +	int display_ver;
> +
> +	igt_fixture {
> +		data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_XE);
And since this is for display_ver >= 30; test should be supported only 
by XE driver.
> +		data.debugfs_fd = igt_debugfs_dir(data.drm_fd);
> +		kmstest_set_vt_graphics_mode();
> +		igt_require_pipe_crc(data.drm_fd);
> +		igt_display_require(&data.display, data.drm_fd);
> +		igt_display_require_output(&data.display);
> +		display_ver = intel_display_ver(intel_get_drm_devid(data.drm_fd));
> +	}
> +
> +	igt_subtest_with_dynamic("fbc-dirty-rectangle-basic") {
> +		data.feature = FEATURE_FBC;
> +		igt_require_f(display_ver >= 30, "FBC with dirty region is not supported\n");
> +		for_each_pipe(&data.display, data.pipe) {
> +			for_each_valid_output_on_pipe(&data.display, data.pipe, data.output) {
> +				data.mode = igt_output_get_mode(data.output);
> +				igt_display_reset(&data.display);
> +				igt_output_set_pipe(data.output, data.pipe);
> +				igt_dynamic_f("%s-%s",
> +					       kmstest_pipe_name(data.pipe),
> +					       igt_output_name(data.output)) {
> +					fbc_dirty_rectangle_basic(&data);
> +				}
> +			}
> +		}
> +	}
> +
> +	igt_subtest_with_dynamic("fbc-dirty-rectangle-different-formats") {
> +		uint32_t formats[] = {DRM_FORMAT_XRGB8888,
> +				      DRM_FORMAT_ARGB8888,
> +				      DRM_FORMAT_RGB565};
> +		int num_formats = ARRAY_SIZE(formats);
> +
> +		data.feature = FEATURE_FBC;
> +		igt_require_f(display_ver >= 30, "FBC with dirty region is not supported\n");
> +
> +		for_each_pipe(&data.display, data.pipe) {
> +			for_each_valid_output_on_pipe(&data.display, data.pipe, data.output) {
> +				data.mode = igt_output_get_mode(data.output);
> +				igt_display_reset(&data.display);
> +				igt_output_set_pipe(data.output, data.pipe);
> +
> +				for (int i = 0; i < num_formats; i++) {
> +					igt_dynamic_f("%s-%s-format-%s",
> +						       kmstest_pipe_name(data.pipe),
> +						       igt_output_name(data.output),
> +						       igt_format_str(formats[i])) {
> +						data.format = formats[i];
> +						fbc_dirty_rectangle_basic(&data);
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	igt_subtest_with_dynamic("fbc-dirty-rectangle-dirtyfb-ioctl") {
> +		data.feature = FEATURE_FBC;
> +		igt_require_f(display_ver >= 30, "FBC with dirty region is not supported\n");
Can we add this check in igt_fixture()? since its common across all 
subtests.
> +
> +		for_each_pipe(&data.display, data.pipe) {
> +			for_each_valid_output_on_pipe(&data.display, data.pipe, data.output) {
> +				data.mode = igt_output_get_mode(data.output);
> +				igt_display_reset(&data.display);
> +				igt_output_set_pipe(data.output, data.pipe);
> +
> +				igt_dynamic_f("%s-%s-dirtyfb-ioctl",
> +					       kmstest_pipe_name(data.pipe),
> +					       igt_output_name(data.output)) {
> +					data.op = FRONTBUFFER;
> +					data.format = DRM_FORMAT_XRGB8888;
> +					fbc_dirty_rectangle_basic(&data);
> +				}
> +			}
> +		}
> +	}
> +
> +	igt_fixture {
> +		igt_display_fini(&data.display);
> +		close(data.drm_fd);
> +	}
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 33dffad31..2ac5ce309 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -268,6 +268,7 @@ intel_kms_progs = [
>   	'kms_psr2_su',
>   	'kms_psr_stress_test',
>   	'kms_pwrite_crc',
> +        'kms_fbc_dirty_rect',
Fix indentation.
>   ]
>   
>   intel_xe_progs = [


More information about the igt-dev mailing list