As we allow userspace to set the dotclock, we should try to respect it! Userpsace will try to set its frametimings based upon the dotclock, so ideally it should match the measured vblank interval. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- tests/kms_setmode.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/tests/kms_setmode.c b/tests/kms_setmode.c index df958f0..966ad93 100644 --- a/tests/kms_setmode.c +++ b/tests/kms_setmode.c @@ -71,6 +71,7 @@ enum test_flags { TEST_SINGLE_CRTC_CLONE = 0x04, TEST_EXCLUSIVE_CRTC_CLONE = 0x08, TEST_STEALING = 0x10, + TEST_TIMINGS = 0x20, }; struct test_config { @@ -413,6 +414,75 @@ static int test_stealing(int fd, struct crtc_config *crtc, uint32_t *ids) return ret; } +static double frame_time(const drmModeModeInfo *kmode) +{ + return 1000.0 * kmode->htotal * kmode->vtotal / kmode->clock; +} + +static void check_timings(int crtc_idx, const drmModeModeInfo *kmode) +{ +#define CALIBRATE_TS_STEPS 120 /* ~2s has to be less than 128! */ + drmVBlank wait; + igt_stats_t stats; + uint32_t last_seq; + uint64_t last_timestamp; + double expected; + double mean; + double stddev; + int n; + + memset(&wait, 0, sizeof(wait)); + wait.request.type = kmstest_get_vbl_flag(crtc_idx); + wait.request.type |= DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS; + do_or_die(drmWaitVBlank(drm_fd, &wait)); + + last_seq = wait.reply.sequence; + last_timestamp = wait.reply.tval_sec; + last_timestamp *= 1000000; + last_timestamp += wait.reply.tval_usec; + + memset(&wait, 0, sizeof(wait)); + wait.request.type = kmstest_get_vbl_flag(crtc_idx); + wait.request.type |= DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + wait.request.sequence = last_seq; + for (n = 0; n < CALIBRATE_TS_STEPS; n++) { + ++wait.request.sequence; + do_or_die(drmWaitVBlank(drm_fd, &wait)); + } + + igt_stats_init_with_size(&stats, CALIBRATE_TS_STEPS); + for (n = 0; n < CALIBRATE_TS_STEPS; n++) { + struct drm_event_vblank ev; + uint64_t now; + + igt_assert(read(drm_fd, &ev, sizeof(ev)) == sizeof(ev)); + igt_assert_eq(ev.sequence, last_seq + 1); + + now = ev.tv_sec; + now *= 1000000; + now += ev.tv_usec; + + igt_stats_push(&stats, now - last_timestamp); + + last_timestamp = now; + last_seq = ev.sequence; + } + + expected = frame_time(kmode); + + mean = igt_stats_get_mean(&stats); + stddev = igt_stats_get_std_deviation(&stats); + + igt_info("Expected frametime: %.0fus; measured %.1fus +- %.3fus accuracy %.2f%%\n", + expected, mean, stddev, 100 * 6 * stddev / mean); + igt_assert(6 * stddev / mean < 0.005); /* 99% accuracy within 0.5% */ + + igt_assert_f(fabs(mean - expected) < 2*stddev, + "vblank interval differs from modeline! expected %.1fus, measured %1.fus +- %.3fus, difference %.1fus (%.1f sigma)\n", + expected, mean, stddev, + fabs(mean - expected), fabs(mean - expected) / stddev); +} + static void test_crtc_config(const struct test_config *tconf, struct crtc_config *crtcs, int crtc_count) { @@ -475,8 +545,8 @@ static void test_crtc_config(const struct test_config *tconf, igt_assert(config_failed == !!(tconf->flags & TEST_INVALID)); - if (ret == 0 && connector_connected && !(tconf->flags & TEST_INVALID)) - sleep(5); + if (ret == 0 && connector_connected && tconf->flags & TEST_TIMINGS) + check_timings(crtcs[0].crtc_idx, &crtcs[0].mode); for (i = 0; i < crtc_count; i++) { if (crtcs[i].fb_info.fb_id) { @@ -732,6 +802,7 @@ int main(int argc, char **argv) enum test_flags flags; const char *name; } tests[] = { + { TEST_TIMINGS, "basic" }, { TEST_CLONE | TEST_SINGLE_CRTC_CLONE, "basic-clone-single-crtc" }, { TEST_INVALID | TEST_CLONE | TEST_SINGLE_CRTC_CLONE, -- 2.10.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx