static void run_test(data_t *data, void (*testfunc)(data_t *), int cursor_w, int cursor_h)
{
	igt_display_t *display = &data->display;
	igt_output_t *output;
	enum pipe p;
	int valid_tests = 0;

	igt_require(cursor_w <= data->cursor_max_w &&
		    cursor_h <= data->cursor_max_h);

	for_each_connected_output(display, output) {
		data->output = output;
		for_each_pipe(display, p) {
			data->pipe = p;

			if (!prepare_crtc(data, output, cursor_w, cursor_h))
				continue;

			valid_tests++;

			igt_info("Beginning %s on pipe %s, connector %s\n",
				 igt_subtest_name(),
				 kmstest_pipe_name(data->pipe),
				 igt_output_name(output));

			testfunc(data);

			igt_info("\n%s on pipe %s, connector %s: PASSED\n\n",
				 igt_subtest_name(),
				 kmstest_pipe_name(data->pipe),
				 igt_output_name(output));

			/* cleanup what prepare_crtc() has done */
			cleanup_crtc(data, output);
		}
/**
 * igt_pipe_crc_stop:
 * @pipe_crc: pipe CRC object
 *
 * Stops the CRC capture process on @pipe_crc.
 */
void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc)
{
	char buf[32];

	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe));
	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
}
static igt_pipe_crc_t *
pipe_crc_new(enum pipe pipe, enum intel_pipe_crc_source source, int flags)
{
	igt_pipe_crc_t *pipe_crc;
	char buf[128];

	igt_install_exit_handler(pipe_crc_exit_handler);

	pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc));

	pipe_crc->ctl_fd = igt_debugfs_open("i915_display_crc_ctl", O_WRONLY);
	igt_assert(pipe_crc->ctl_fd != -1);

	sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe));
	pipe_crc->crc_fd = igt_debugfs_open(buf, flags);
	igt_assert(pipe_crc->crc_fd != -1);

	pipe_crc->line_len = PIPE_CRC_LINE_LEN;
	pipe_crc->buffer_len = PIPE_CRC_BUFFER_LEN;
	pipe_crc->pipe = pipe;
	pipe_crc->source = source;
	pipe_crc->flags = flags;

	return pipe_crc;
}
static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe)
{
	char buf[32];

	sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe));
	igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf));
}
static void test_read_crc(data_t *data, int pipe, unsigned flags)
{
	igt_display_t *display = &data->display;
	int valid_connectors = 0;
	igt_output_t *output;

	igt_skip_on(pipe >= data->display.n_pipes);

	for_each_connected_output(display, output) {

		igt_info("%s: Testing connector %s using pipe %s\n",
			 igt_subtest_name(), igt_output_name(output),
			 kmstest_pipe_name(pipe));

		valid_connectors += test_read_crc_for_output(data, pipe, output, flags);
	}
static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc)
{
	char buf[64];

	/* Stop first just to make sure we don't have lingering state left. */
	igt_pipe_crc_stop(pipe_crc);

	sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe),
		pipe_crc_source_name(pipe_crc->source));
	errno = 0;
	igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf));
	if (errno != 0)
		return false;

	return true;
}
static int test_format(const char *test_name,
		       struct kmstest_connector_config *cconf,
		       drmModeModeInfo *mode, uint32_t format,
		       enum test_flags flags)
{
	int width;
	int height;
	struct igt_fb fb[2];
	char *mode_format_str;
	char *cconf_str;
	int ret;

	ret = asprintf(&mode_format_str, "%s @ %dHz / %s",
		 mode->name, mode->vrefresh, igt_format_str(format));
	igt_assert_lt(0, ret);
	ret = asprintf(&cconf_str, "pipe %s, encoder %s, connector %s",
		       kmstest_pipe_name(cconf->pipe),
		       kmstest_encoder_type_str(cconf->encoder->encoder_type),
		       kmstest_connector_type_str(cconf->connector->connector_type));
	igt_assert_lt(0, ret);

	igt_info("Beginning test %s with %s on %s\n",
		 test_name, mode_format_str, cconf_str);

	width = mode->hdisplay;
	height = mode->vdisplay;

	if (!igt_create_fb(drm_fd, width, height, format,
			   LOCAL_DRM_FORMAT_MOD_NONE, &fb[0]))
		goto err1;

	if (!igt_create_fb(drm_fd, width, height, format,
			   LOCAL_DRM_FORMAT_MOD_NONE,	&fb[1]))
		goto err2;

	if (drmModeSetCrtc(drm_fd, cconf->crtc->crtc_id, fb[0].fb_id,
				 0, 0, &cconf->connector->connector_id, 1,
				 mode))
		goto err2;
	do_or_die(drmModePageFlip(drm_fd, cconf->crtc->crtc_id, fb[0].fb_id,
				  0, NULL));
	sleep(2);

	if (flags & TEST_DIRECT_RENDER) {
		paint_fb(&fb[0], test_name, mode_format_str, cconf_str);
	} else if (flags & TEST_GPU_BLIT) {
		paint_fb(&fb[1], test_name, mode_format_str, cconf_str);
		gpu_blit(&fb[0], &fb[1]);
	}
	sleep(5);

	igt_info("Test %s with %s on %s: PASSED\n",
		 test_name, mode_format_str, cconf_str);
	free(mode_format_str);
	free(cconf_str);

	igt_remove_fb(drm_fd, &fb[1]);
	igt_remove_fb(drm_fd, &fb[0]);

	return 0;

err2:
	igt_remove_fb(drm_fd, &fb[0]);
err1:
	igt_info("Test %s with %s on %s: SKIPPED\n",
		 test_name, mode_format_str, cconf_str);
	free(mode_format_str);
	free(cconf_str);

	return -1;
}