summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-08-29 16:00:51 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-08-29 16:19:41 +0100
commit1f2b3e99f9349dbc34750d506312b6eb353c14a4 (patch)
tree779e79199e7ba7fb579ee40aeecc30a61def5228
parent919d68901187fa797a9b648fcf87c838fae22fa3 (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.c222
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();