diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-29 16:00:51 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-08-29 16:19:41 +0100 |
commit | 1f2b3e99f9349dbc34750d506312b6eb353c14a4 (patch) | |
tree | 779e79199e7ba7fb579ee40aeecc30a61def5228 | |
parent | 919d68901187fa797a9b648fcf87c838fae22fa3 (diff) |
kms_flip: Run on pairs of connected outputs.
The goal is to flip the same framebuffer on a pair of CRTCs (clone mode)
and check that (a) the flip works in all combinations of workloads, and
(b) that we can hit the desired refresh rate under the simplest, most
ideal of conditions.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | tests/kms_flip.c | 222 |
1 files changed, 209 insertions, 13 deletions
diff --git a/tests/kms_flip.c b/tests/kms_flip.c index aaab80b7..6eb13d55 100644 --- a/tests/kms_flip.c +++ b/tests/kms_flip.c @@ -911,6 +911,69 @@ static void connector_find_preferred_mode(uint32_t connector_id, int crtc_idx, } +static bool mode_compatible(const drmModeModeInfo *a, const drmModeModeInfo *b) +{ + int d_refresh; + + if (a->hdisplay != b->hdisplay) + return false; + + if (a->vdisplay != b->vdisplay) + return false; + + d_refresh = a->vrefresh - b->vrefresh; + if (d_refresh < -1 || d_refresh > 1) + return false; + + return true; +} + +static void connector_find_compatible_mode(int crtc_idx0, int crtc_idx1, + struct test_output *o) +{ + struct kmstest_connector_config config[2]; + drmModeModeInfo *mode[2]; + int n, m; + + if (kmstest_get_connector_config(drm_fd, o->_connector[0], + 1 << crtc_idx0, &config[0]) < 0) + return; + + if (kmstest_get_connector_config(drm_fd, o->_connector[1], + 1 << crtc_idx1, &config[1]) < 0) + return; + + mode[0] = &config[0].default_mode; + mode[1] = &config[1].default_mode; + if (!mode_compatible(mode[0], mode[1])) { + for (n = 0; n < config[0].connector->count_modes; n++) { + mode[0] = &config[0].connector->modes[n]; + for (m = 0; m < config[1].connector->count_modes; m++) { + mode[1] = &config[1].connector->modes[m]; + if (mode_compatible(mode[0], mode[1])) + goto found; + } + } + return; + } + +found: + o->pipe = config[0].pipe; + o->fb_width = mode[0]->hdisplay; + o->fb_height = mode[0]->vdisplay; + o->mode_valid = 1; + + o->kconnector[0] = config[0].connector; + o->kencoder[0] = config[0].encoder; + o->_crtc[0] = config[0].crtc->crtc_id; + o->kmode[0] = *mode[0]; + + o->kconnector[1] = config[1].connector; + o->kencoder[1] = config[1].encoder; + o->_crtc[1] = config[1].crtc->crtc_id; + o->kmode[1] = *mode[1]; +} + static void paint_flip_mode(struct kmstest_fb *fb, bool odd_frame) { cairo_t *cr = kmstest_get_cairo_ctx(drm_fd, fb); @@ -950,7 +1013,7 @@ fb_is_bound(struct test_output *o, int fb) } static void check_final_state(struct test_output *o, struct event_state *es, - unsigned int ellapsed) + unsigned int elapsed) { if (es->count == 0) { fprintf(stderr, "no %s event received\n", es->name); @@ -964,7 +1027,7 @@ static void check_final_state(struct test_output *o, struct event_state *es, int count = es->count; count *= es->seq_step; - expected = ellapsed * o->kmode[0].vrefresh / (1000 * 1000); + expected = elapsed * o->kmode[0].vrefresh / (1000 * 1000); if (count < expected * 99/100) { fprintf(stderr, "dropped frames, expected %d, counted %d, encoder type %d\n", expected, count, o->kencoder[0]->encoder_type); @@ -1020,7 +1083,7 @@ static unsigned int wait_for_events(struct test_output *o) return event_mask; } -/* Returned the ellapsed time in us */ +/* Returned the elapsed time in us */ static unsigned event_loop(struct test_output *o, unsigned duration_sec) { unsigned long start, end; @@ -1051,7 +1114,7 @@ static unsigned event_loop(struct test_output *o, unsigned duration_sec) static void run_test_on_crtc(struct test_output *o, int crtc_idx, int duration) { - unsigned ellapsed; + unsigned elapsed; o->bpp = 32; o->depth = 24; @@ -1117,12 +1180,12 @@ static void run_test_on_crtc(struct test_output *o, int crtc_idx, int duration) else o->vblank_state.seq_step = 1; - ellapsed = event_loop(o, duration); + elapsed = event_loop(o, duration); if (o->flags & TEST_FLIP && !(o->flags & TEST_NOEVENT)) - check_final_state(o, &o->flip_state, ellapsed); + check_final_state(o, &o->flip_state, elapsed); if (o->flags & TEST_VBLANK) - check_final_state(o, &o->vblank_state, ellapsed); + check_final_state(o, &o->vblank_state, elapsed); fprintf(stdout, "\n%s on crtc %d, connector %d: PASSED\n\n", igt_subtest_name(), o->_crtc[0], o->_connector[0]); @@ -1138,11 +1201,103 @@ out: drmModeFreeConnector(o->kconnector[0]); } +static void run_test_on_crtc_pair(struct test_output *o, int crtc_idx0, int crtc_idx1, int duration) +{ + unsigned elapsed; + int i; + + o->bpp = 32; + o->depth = 24; + + connector_find_compatible_mode(crtc_idx0, crtc_idx1, o); + if (!o->mode_valid) + return; + + last_connector = o->kconnector[0]; + + fprintf(stdout, "Beginning %s on crtc %d:%d, connector %d:%d\n", + igt_subtest_name(), o->_crtc[0], o->_crtc[1], o->_connector[0], o->_connector[1]); + + if (o->flags & TEST_PAN) + o->fb_width *= 2; + + o->fb_ids[0] = kmstest_create_fb(drm_fd, o->fb_width, o->fb_height, + o->bpp, o->depth, false, &o->fb_info[0]); + o->fb_ids[1] = kmstest_create_fb(drm_fd, o->fb_width, o->fb_height, + o->bpp, o->depth, false, &o->fb_info[1]); + o->fb_ids[2] = kmstest_create_fb(drm_fd, o->fb_width, o->fb_height, + o->bpp, o->depth, true, &o->fb_info[2]); + + if (!o->fb_ids[0] || !o->fb_ids[1] || !o->fb_ids[2]) { + fprintf(stderr, "failed to create fbs\n"); + igt_fail(3); + } + + paint_flip_mode(&o->fb_info[0], false); + paint_flip_mode(&o->fb_info[1], true); + paint_flip_mode(&o->fb_info[2], true); + + set_y_tiling(o, 2); + + kmstest_dump_mode(&o->kmode[0]); + kmstest_dump_mode(&o->kmode[1]); + if (set_mode(o, o->fb_ids[0], 0, 0)) { + /* We may fail to apply the mode if there are hidden + * constraints, such as bandwidth on the third pipe. + */ + if (0) { + fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n", + o->fb_width, o->fb_height, o->kmode[0].vrefresh, + strerror(errno)); + } + goto out; + } + igt_assert(fb_is_bound(o, o->fb_ids[0])); + + /* quiescent the hw a bit so ensure we don't miss a single frame */ + if (o->flags & TEST_CHECK_TS) + sleep(1); + + if (do_page_flip(o, o->fb_ids[1], true)) { + fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); + igt_fail(4); + } + wait_for_events(o); + + 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; + + elapsed = event_loop(o, duration); + + if (o->flags & TEST_FLIP && !(o->flags & TEST_NOEVENT)) + check_final_state(o, &o->flip_state, elapsed); + if (o->flags & TEST_VBLANK) + check_final_state(o, &o->vblank_state, elapsed); + + fprintf(stdout, "\n%s on crtc %d:%d, connector %d:%d: PASSED\n\n", + igt_subtest_name(), o->_crtc[0], o->_crtc[1], o->_connector[0], o->_connector[1]); + +out: + kmstest_remove_fb(drm_fd, &o->fb_info[2]); + kmstest_remove_fb(drm_fd, &o->fb_info[1]); + kmstest_remove_fb(drm_fd, &o->fb_info[0]); + + last_connector = NULL; + + for (i = 0; i < o->count; i++) { + drmModeFreeEncoder(o->kencoder[i]); + drmModeFreeConnector(o->kconnector[i]); + } +} + static int run_test(int duration, int flags) { struct test_output o; - int c; - int crtc_idx; + int i, n; resources = drmModeGetResources(drm_fd); if (!resources) { @@ -1152,16 +1307,51 @@ static int run_test(int duration, int flags) } /* Find any connected displays */ - for (c = 0; c < resources->count_connectors; c++) { - for (crtc_idx = 0; crtc_idx < resources->count_crtcs; crtc_idx++) { + for (i = 0; i < resources->count_connectors; i++) { + for (n = 0; n < resources->count_crtcs; n++) { memset(&o, 0, sizeof(o)); o.count = 1; - o._connector[0] = resources->connectors[c]; + o._connector[0] = resources->connectors[i]; o.flags = flags; o.flip_state.name = "flip"; o.vblank_state.name = "vblank"; - run_test_on_crtc(&o, crtc_idx, duration); + run_test_on_crtc(&o, n, duration); + } + } + + drmModeFreeResources(resources); + return 1; +} + +static int run_pair(int duration, int flags) +{ + struct test_output o; + int i, j, m, n; + + resources = drmModeGetResources(drm_fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + igt_fail(5); + } + + /* Find a pair of connected displays */ + for (i = 0; i < resources->count_connectors; i++) { + for (n = 0; n < resources->count_crtcs; n++) { + for (j = i + 1; j < resources->count_connectors; j++) { + for (m = n + 1; m < resources->count_crtcs; m++) { + memset(&o, 0, sizeof(o)); + o.count = 2; + o._connector[0] = resources->connectors[i]; + o._connector[1] = resources->connectors[j]; + o.flags = flags; + o.flip_state.name = "flip"; + o.vblank_state.name = "vblank"; + + run_test_on_crtc_pair(&o, n, m, duration); + } + } } } @@ -1265,6 +1455,9 @@ int main(int argc, char **argv) for (i = 0; i < sizeof(tests) / sizeof (tests[0]); i++) { igt_subtest(tests[i].name) run_test(tests[i].duration, tests[i].flags); + + igt_subtest_f( "2x-%s", tests[i].name) + run_pair(tests[i].duration, tests[i].flags); } igt_fork_signal_helper(); @@ -1277,6 +1470,9 @@ int main(int argc, char **argv) igt_subtest_f( "%s-interruptible", tests[i].name) run_test(tests[i].duration, tests[i].flags); + + igt_subtest_f( "2x-%s-interruptible", tests[i].name) + run_pair(tests[i].duration, tests[i].flags); } igt_stop_signal_helper(); |