[22/22] flip_test: add wait-for-vblank tests
diff mbox

Message ID 1350398096-3649-23-git-send-email-imre.deak@intel.com
State New, archived
Headers show

Commit Message

Imre Deak Oct. 16, 2012, 2:34 p.m. UTC
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 tests/flip_test.c |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 126 insertions(+), 4 deletions(-)

Patch
diff mbox

diff --git a/tests/flip_test.c b/tests/flip_test.c
index 2b70f2a..7c3d0f2 100644
--- a/tests/flip_test.c
+++ b/tests/flip_test.c
@@ -49,8 +49,12 @@ 
 #define TEST_EBUSY		(1 << 5)
 #define TEST_EINVAL		(1 << 6)
 #define TEST_FLIP		(1 << 7)
+#define TEST_VBLANK		(1 << 8)
+#define TEST_VBLANK_BLOCK	(1 << 9)
+#define TEST_VBLANK_ABSOLUTE	(1 << 10)
 
 #define EVENT_FLIP		(1 << 0)
+#define EVENT_VBLANK		(1 << 1)
 
 drmModeRes *resources;
 int drm_fd;
@@ -108,6 +112,7 @@  struct test_output {
 	struct kmstest_fb fb_info[2];
 
 	struct event_state flip_state;
+	struct event_state vblank_state;
 	unsigned int pending_events;
 };
 
@@ -211,6 +216,51 @@  static int do_page_flip(struct test_output *o, int fb_id)
 	return ret;
 }
 
+struct vblank_reply {
+	unsigned int sequence;
+	struct timeval ts;
+};
+
+static int do_wait_for_vblank(struct test_output *o, int crtc_idx,
+			      int target_seq, struct vblank_reply *reply)
+{
+	drmVBlank wait_vbl;
+	int ret;
+	unsigned crtc_idx_mask;
+	bool event = !(o->flags & TEST_VBLANK_BLOCK);
+
+	memset(&wait_vbl, 0, sizeof(wait_vbl));
+
+	crtc_idx_mask = crtc_idx << DRM_VBLANK_HIGH_CRTC_SHIFT;
+	assert(!(crtc_idx_mask & ~DRM_VBLANK_HIGH_CRTC_MASK));
+
+	wait_vbl.request.type = crtc_idx_mask;
+	if (o->flags & TEST_VBLANK_ABSOLUTE)
+		wait_vbl.request.type |= DRM_VBLANK_ABSOLUTE;
+	else
+		wait_vbl.request.type |= DRM_VBLANK_RELATIVE;
+	if (event) {
+		wait_vbl.request.type |= DRM_VBLANK_EVENT;
+		wait_vbl.request.signal = (unsigned long)o;
+	}
+	wait_vbl.request.sequence = target_seq;
+
+	ret = drmWaitVBlank(drm_fd, &wait_vbl);
+
+	if (ret == 0) {
+		reply->ts.tv_sec = wait_vbl.reply.tval_sec;
+		reply->ts.tv_usec = wait_vbl.reply.tval_usec;
+		reply->sequence = wait_vbl.reply.sequence;
+
+		if (event) {
+			assert(!(o->pending_events & EVENT_VBLANK));
+			o->pending_events |= EVENT_VBLANK;
+		}
+	}
+
+	return ret;
+}
+
 static bool
 analog_tv_connector(struct test_output *o)
 {
@@ -240,6 +290,15 @@  static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
 	event_handler(&o->flip_state, frame, sec, usec);
 }
 
+static void vblank_handler(int fd, unsigned int frame, unsigned int sec,
+			      unsigned int usec, void *data)
+{
+	struct test_output *o = data;
+
+	clear_flag(&o->pending_events, EVENT_VBLANK);
+	event_handler(&o->vblank_state, frame, sec, usec);
+}
+
 static void check_state(struct test_output *o, struct event_state *es)
 {
 	struct timeval diff;
@@ -299,6 +358,8 @@  static void check_all_state(struct test_output *o,
 {
 	if (completed_events & EVENT_FLIP)
 		check_state(o, &o->flip_state);
+	if (completed_events & EVENT_VBLANK)
+		check_state(o, &o->vblank_state);
 }
 
 /* Return mask of completed events. */
@@ -309,12 +370,16 @@  static unsigned int run_test_step(struct test_output *o)
 	int expected_einval = o->flags & TEST_MODESET ? -EBUSY : -EINVAL;
 	unsigned int completed_events = 0;
 	bool do_flip;
+	bool do_vblank;
 
 	do_flip = (o->flags & TEST_FLIP) && !(o->pending_events & EVENT_FLIP);
+	do_vblank = (o->flags & TEST_VBLANK) &&
+		    !(o->pending_events & EVENT_VBLANK);
 
 	/* pan before the flip completes */
 	if (o->flags & TEST_PAN) {
-		int count = o->flip_state.count;
+		int count = do_flip ?
+			o->flip_state.count : o->vblank_state.count;
 		int x_ofs = count * 10 > o->mode.hdisplay ?
 			    o->mode.hdisplay : count * 10;
 
@@ -356,6 +421,24 @@  static unsigned int run_test_step(struct test_output *o)
 	if (do_flip)
 		do_or_die(do_page_flip(o, new_fb_id));
 
+	if (do_vblank) {
+		struct vblank_reply vbl_reply;
+		unsigned int target_seq;
+
+		target_seq = o->vblank_state.seq_step;
+		if (o->flags & TEST_VBLANK_ABSOLUTE)
+			target_seq += o->vblank_state.last_seq;
+
+		do_or_die(do_wait_for_vblank(o, o->crtc_idx, target_seq,
+					     &vbl_reply));
+		if (o->flags & TEST_VBLANK_BLOCK) {
+			event_handler(&o->vblank_state, vbl_reply.sequence,
+				      vbl_reply.ts.tv_sec,
+				      vbl_reply.ts.tv_usec);
+			completed_events = EVENT_VBLANK;
+		}
+	}
+
 	if (do_flip && (o->flags & TEST_EBUSY))
 		assert(do_page_flip(o, new_fb_id) == -EBUSY);
 
@@ -392,6 +475,9 @@  static void update_all_state(struct test_output *o,
 {
 	if (completed_events & EVENT_FLIP)
 		update_state(&o->flip_state);
+
+	if (completed_events & EVENT_VBLANK)
+		update_state(&o->vblank_state);
 }
 
 static void connector_find_preferred_mode(struct test_output *o, int crtc_id)
@@ -554,7 +640,7 @@  static unsigned int wait_for_events(struct test_output *o)
 
 	memset(&evctx, 0, sizeof evctx);
 	evctx.version = DRM_EVENT_CONTEXT_VERSION;
-	evctx.vblank_handler = NULL;
+	evctx.vblank_handler = vblank_handler;
 	evctx.page_flip_handler = page_flip_handler;
 
 	/* make timeout lax with the dummy load */
@@ -611,10 +697,14 @@  static unsigned event_loop(struct test_output *o, unsigned duration_sec)
 	gettimeofday(&end, NULL);
 	timersub(&end, &start, &tv_dur);
 
+	/* Flush any remaining events */
+	if (o->pending_events)
+		wait_for_events(o);
+
 	return tv_dur.tv_sec * 1000 * 1000 + tv_dur.tv_usec;
 }
 
-static void flip_mode(struct test_output *o, int duration)
+static void run_test_on_crtc(struct test_output *o, int duration)
 {
 	int bpp = 32, depth = 24;
 	unsigned ellapsed;
@@ -661,6 +751,7 @@  static void flip_mode(struct test_output *o, int duration)
 		sleep(1);
 
 	gettimeofday(&o->flip_state.last_ts, NULL);
+	gettimeofday(&o->vblank_state.last_ts, NULL);
 
 	if (do_page_flip(o, o->fb_ids[1])) {
 		fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
@@ -670,11 +761,17 @@  static void flip_mode(struct test_output *o, int duration)
 
 	o->current_fb_id = 1;
 	o->flip_state.seq_step = 1;
+	if (o->flags & TEST_VBLANK_ABSOLUTE)
+		o->vblank_state.seq_step = 5;
+	else
+		o->vblank_state.seq_step = 1;
 
 	ellapsed = event_loop(o, duration);
 
 	if (o->flags & TEST_FLIP)
 		check_final_state(o, &o->flip_state, ellapsed);
+	if (o->flags & TEST_VBLANK)
+		check_final_state(o, &o->vblank_state, ellapsed);
 
 	fprintf(stdout, "\n%s on crtc %d, connector %d: PASSED\n\n",
 		o->test_name, crtc, o->id);
@@ -706,9 +803,10 @@  static int run_test(int duration, int flags, const char *test_name)
 			o.id = resources->connectors[c];
 			o.flags = flags;
 			o.flip_state.name = "flip";
+			o.vblank_state.name = "vblank";
 			o.crtc_idx = i;
 
-			flip_mode(&o, duration);
+			run_test_on_crtc(&o, duration);
 		}
 	}
 
@@ -723,6 +821,23 @@  int main(int argc, char **argv)
 		int flags;
 		const char *name;
 	} tests[] = {
+		{ 30, TEST_VBLANK | TEST_CHECK_TS, "wf-vblank" },
+		{ 30, TEST_VBLANK | TEST_VBLANK_BLOCK | TEST_CHECK_TS,
+					"blocking wf-vblank" },
+		{ 5,  TEST_VBLANK | TEST_VBLANK_ABSOLUTE,
+					"absolute wf-vblank" },
+		{ 5,  TEST_VBLANK | TEST_VBLANK_BLOCK | TEST_VBLANK_ABSOLUTE,
+					"blocking absolute wf-vblank" },
+		{ 5,  TEST_VBLANK | TEST_DPMS, "wf-vblank vs dpms" },
+		{ 5,  TEST_VBLANK | TEST_DPMS | TEST_WITH_DUMMY_LOAD,
+					"delayed wf-vblank vs dpms" },
+		{ 5,  TEST_VBLANK | TEST_PAN, "wf-vblank vs panning" },
+		{ 5,  TEST_VBLANK | TEST_PAN | TEST_WITH_DUMMY_LOAD,
+					"delayed wf-vblank vs panning" },
+		{ 5,  TEST_VBLANK | TEST_MODESET, "wf-vblank vs modeset" },
+		{ 5,  TEST_VBLANK | TEST_MODESET | TEST_WITH_DUMMY_LOAD,
+					"delayed wf-vblank vs modeset" },
+
 		{ 15, TEST_FLIP | TEST_CHECK_TS | TEST_EBUSY , "plain flip" },
 		{ 30, TEST_FLIP | TEST_DPMS | TEST_EINVAL, "flip vs dpms" },
 		{ 30, TEST_FLIP | TEST_DPMS | TEST_WITH_DUMMY_LOAD, "delayed flip vs dpms" },
@@ -730,6 +845,13 @@  int main(int argc, char **argv)
 		{ 30, TEST_FLIP | TEST_PAN | TEST_WITH_DUMMY_LOAD, "delayed flip vs panning" },
 		{ 30, TEST_FLIP | TEST_MODESET | TEST_EINVAL, "flip vs modeset" },
 		{ 30, TEST_FLIP | TEST_MODESET | TEST_WITH_DUMMY_LOAD, "delayed flip vs modeset" },
+
+		{ 30, TEST_FLIP | TEST_VBLANK | TEST_VBLANK_ABSOLUTE |
+		      TEST_CHECK_TS, "flip vs absolute wf-vblank" },
+		{ 30, TEST_FLIP | TEST_VBLANK | TEST_CHECK_TS,
+					"flip vs wf-vblank" },
+		{ 30, TEST_FLIP | TEST_VBLANK | TEST_VBLANK_BLOCK |
+			TEST_CHECK_TS, "flip vs blocking wf-vblank" },
 	};
 	int i;