[igt-dev] [PATCH i-g-t 3/3] tests/kms_dirtyfb: Add new test for dirtyfb ioctl

Jouni Högander jouni.hogander at intel.com
Wed Apr 5 05:34:51 UTC 2023


Add new test to validate dirtyfb ioctl is working properly with GPU
frontbuffer rendering.

Create big framebuffer and use only lower right corner for the
plane. Initiate GPU drawing for a rectangle over the whole
framebuffer and perform dirtyfb ioctl. Then wait for the drawing to
complete and collect crc and check that it matches with expected.

Signed-off-by: Jouni Högander <jouni.hogander at intel.com>
---
 tests/i915/kms_dirtyfb.c | 309 +++++++++++++++++++++++++++++++++++++++
 tests/meson.build        |   8 +
 2 files changed, 317 insertions(+)
 create mode 100644 tests/i915/kms_dirtyfb.c

diff --git a/tests/i915/kms_dirtyfb.c b/tests/i915/kms_dirtyfb.c
new file mode 100644
index 00000000..99d4231d
--- /dev/null
+++ b/tests/i915/kms_dirtyfb.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright © 2023 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <sys/types.h>
+
+#include "igt.h"
+#include "igt_psr.h"
+
+#include "kms_fbc_helper.h"
+#include "kms_drrs_helper.h"
+
+IGT_TEST_DESCRIPTION("Test the DIRTYFB ioctl is working properly with "
+		     "its related features: FBC, PSR and DRRS");
+
+#ifndef PAGE_ALIGN
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE)
+#endif
+
+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;
+
+	struct igt_fb fbs[3];
+
+	igt_crc_t ref_crc;
+
+	struct buf_ops *bops;
+	enum {
+		FEATURE_NONE  = 0,
+		FEATURE_PSR   = 1,
+		FEATURE_FBC   = 2,
+		FEATURE_DRRS  = 4,
+		FEATURE_COUNT = 8,
+		FEATURE_DEFAULT = 8,
+	} feature;
+} data_t;
+
+static const char *feature_str(int feature)
+{
+	switch (feature) {
+	case FEATURE_NONE:
+		return "nop";
+	case FEATURE_FBC:
+		return "fbc";
+	case FEATURE_PSR:
+		return "psr";
+	case FEATURE_DRRS:
+		return "drrs";
+	case FEATURE_DEFAULT:
+		return "default";
+	default:
+		igt_assert(false);
+	}
+}
+
+static bool check_support(data_t *data)
+{
+	switch (data->feature) {
+	case FEATURE_NONE:
+		return true;
+	case FEATURE_FBC:
+		return fbc_supported_on_chipset(data->drm_fd, data->pipe);
+	case FEATURE_PSR:
+		return psr_sink_support(data->drm_fd, data->debugfs_fd,
+					PSR_MODE_1);
+	case FEATURE_DRRS:
+		return is_drrs_supported(data->drm_fd, data->pipe) &&
+			output_has_drrs(data->drm_fd, data->output);
+	case FEATURE_DEFAULT:
+		return true;
+	default:
+		igt_assert(false);
+	}
+}
+
+static void enable_feature(data_t *data)
+{
+	switch (data->feature) {
+	case FEATURE_NONE:
+		break;
+	case FEATURE_FBC:
+		fbc_enable(data->drm_fd);
+		break;
+	case FEATURE_PSR:
+		psr_enable(data->drm_fd, data->debugfs_fd, PSR_MODE_1);
+		break;
+	case FEATURE_DRRS:
+		drrs_enable(data->drm_fd, data->pipe);
+		break;
+	case FEATURE_DEFAULT:
+		break;
+	default:
+		igt_assert(false);
+	}
+}
+
+static void check_feature(data_t *data)
+{
+	switch (data->feature) {
+	case FEATURE_NONE:
+		break;
+	case FEATURE_FBC:
+		igt_assert_f(fbc_wait_until_enabled(data->drm_fd, data->pipe),
+			     "FBC still disabled");
+		break;
+	case FEATURE_PSR:
+		igt_assert_f(psr_wait_entry(data->debugfs_fd, PSR_MODE_1),
+			     "PSR still disabled\n");
+		break;
+	case FEATURE_DRRS:
+		igt_assert_f(is_drrs_inactive(data->drm_fd, data->pipe),
+			     "DRRS INACTIVE\n");
+		break;
+	case FEATURE_DEFAULT:
+		break;
+	default:
+		igt_assert(false);
+	}
+}
+
+static void disable_features(data_t *data)
+{
+	fbc_disable(data->drm_fd);
+	psr_disable(data->drm_fd, data->debugfs_fd);
+	drrs_disable(data->drm_fd, data->pipe);
+}
+
+static void prepare(data_t *data)
+{
+	igt_plane_t *primary;
+	drmModeResPtr res;
+
+	igt_skip_on(!check_support(data));
+
+	data->mode = igt_output_get_mode(data->output);
+
+	igt_output_set_pipe(data->output, data->pipe);
+
+	data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+					 IGT_PIPE_CRC_SOURCE_AUTO);
+
+	igt_create_color_fb(data->drm_fd, data->mode->hdisplay,
+			    data->mode->hdisplay, DRM_FORMAT_XRGB8888,
+			    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
+			    &data->fbs[0]);
+	igt_draw_rect_fb(data->drm_fd, data->bops, 0, &data->fbs[0],
+			 IGT_DRAW_RENDER, 0, 0, data->fbs[0].width,
+			 data->fbs[0].height, 0xFF);
+
+	primary = igt_output_get_plane_type(data->output,
+					    DRM_PLANE_TYPE_PRIMARY);
+
+	igt_plane_set_fb(primary, &data->fbs[0]);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+
+	res = drmModeGetResources(data->drm_fd);
+
+	igt_create_color_fb(data->drm_fd, res->max_width,
+			    res->max_height, DRM_FORMAT_XRGB8888,
+			    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
+			    &data->fbs[1]);
+	igt_draw_rect_fb(data->drm_fd, data->bops, 0, &data->fbs[1],
+			 IGT_DRAW_MMAP_CPU, 0, 0, data->fbs[1].width,
+			 data->fbs[1].height, 0xFF);
+
+	igt_create_color_fb(data->drm_fd, res->max_width,
+			    res->max_height, DRM_FORMAT_XRGB8888,
+			    DRM_FORMAT_MOD_LINEAR, 0.0, 1.0, 0.0,
+			    &data->fbs[2]);
+
+	igt_plane_set_fb(primary, &data->fbs[2]);
+	igt_fb_set_position(&data->fbs[2], primary,
+			    data->fbs[2].width - data->fbs[0].width,
+			    data->fbs[2].height - data->fbs[0].height);
+	igt_fb_set_size(&data->fbs[2], primary, data->fbs[0].width,
+			data->fbs[0].height);
+
+	enable_feature(data);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	check_feature(data);
+}
+
+static void cleanup(data_t *data)
+{
+	igt_remove_fb(data->drm_fd, &data->fbs[0]);
+	igt_remove_fb(data->drm_fd, &data->fbs[1]);
+
+	igt_pipe_crc_free(data->pipe_crc);
+
+	disable_features(data);
+
+	igt_output_set_pipe(data->output, PIPE_NONE);
+
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+}
+
+static void run_test(data_t *data)
+{
+	igt_crc_t crc;
+	struct intel_buf *src, *dst;
+	struct intel_bb *ibb;
+	uint32_t devid = intel_get_drm_devid(data->drm_fd);
+	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
+	int r;
+
+	igt_skip_on(!rendercopy);
+
+	src = intel_buf_create_using_handle(data->bops, data->fbs[1].gem_handle,
+					    data->fbs[1].width,
+					    data->fbs[1].height,
+					    igt_drm_format_to_bpp(data->fbs[1].drm_format),
+					    0, igt_fb_mod_to_tiling(data->fbs[1].modifier), 0);
+	dst = intel_buf_create_using_handle(data->bops, data->fbs[2].gem_handle,
+					    data->fbs[2].width,
+					    data->fbs[2].height,
+					    igt_drm_format_to_bpp(data->fbs[2].drm_format),
+					    0, igt_fb_mod_to_tiling(data->fbs[2].modifier), 0);
+	ibb = intel_bb_create_with_context(data->drm_fd, 0, NULL, PAGE_SIZE);
+
+	rendercopy(ibb, src, 0, 0, data->fbs[2].width, data->fbs[2].height, dst, 0, 0);
+
+	/* Perfom dirtyfb right after initiating rendercopy */
+	r = drmModeDirtyFB(data->drm_fd, data->fbs[2].fb_id, NULL, 0);
+	igt_assert(r == 0 || r == -ENOSYS);
+
+	/* Ensure rendercopy is complete */
+	intel_bb_sync(ibb);
+
+	intel_bb_destroy(ibb);
+	intel_buf_destroy(src);
+	intel_buf_destroy(dst);
+
+	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
+	igt_assert_crc_equal(&crc, &data->ref_crc);
+}
+
+igt_main
+{
+	data_t data = {};
+
+	igt_fixture {
+		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+		data.debugfs_fd = igt_debugfs_dir(data.drm_fd);
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_require(&data.display, data.drm_fd);
+
+		data.bops = buf_ops_create(data.drm_fd);
+
+		igt_display_reset(&data.display);
+	}
+
+	igt_describe("Test dirtyFB ioctl");
+	igt_subtest_with_dynamic("dirtyfb-ioctl") {
+		data.pipe = PIPE_A;
+		for_each_valid_output_on_pipe(&data.display, data.pipe,
+					      data.output) {
+			for (data.feature = FEATURE_DEFAULT; data.feature > 0;
+			     data.feature = data.feature >> 1) {
+				igt_dynamic_f("%s-%s", feature_str(data.feature),
+					      igt_output_name(data.output)) {
+					prepare(&data);
+					run_test(&data);
+					cleanup(&data);
+				}
+			}
+		}
+	}
+
+	igt_fixture {
+		buf_ops_destroy(data.bops);
+		igt_display_fini(&data.display);
+		close(data.drm_fd);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 8fa69af3..a286a9b8 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -494,6 +494,14 @@ test_executables += executable('kms_frontbuffer_tracking',
 	   install : true)
 test_list += 'kms_frontbuffer_tracking'
 
+test_executables += executable('kms_dirtyfb',
+	   [ join_paths('i915', 'kms_dirtyfb.c'), join_paths ('i915', 'kms_fbc_helper.c'), join_paths ('i915', 'kms_drrs_helper.c')],
+	   dependencies : test_deps,
+	   install_dir : libexecdir,
+	   install_rpath : libexecdir_rpathdir,
+	   install : true)
+test_list += 'kms_frontbuffer_tracking'
+
 if chamelium.found()
        test_executables += executable('kms_chamelium_color',
                              [ 'chamelium/kms_chamelium_color.c', 'kms_color_helper.c' ],
-- 
2.34.1



More information about the igt-dev mailing list