summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmil Velikov <emil.velikov@collabora.com>2019-07-22 13:08:23 -0300
committerEmil Velikov <emil.l.velikov@gmail.com>2020-05-19 21:09:35 +0100
commitbf602a2d6794878a5ef3676254d33ba018c6f2a7 (patch)
tree6bebea06c1520618bd3fe73a2b2cec5ed574a1c2
parenta04c8abb86362e39a5a74caddf923356dec8d61f (diff)
modetest: Add a new "-r" option to set a default mode
This option finds all connected connector and then sets its preferred mode on it. If no preferred mode is available, first mode is used. This option must be set w/o any mode or plane. This allows for a quick test on all connected outputs. Loosely based on the work by Ezequiel Garcia <ezequiel@collabora.com> Changes since Ezequiel's work: - implement atomic codepath - set all connectors - pick correct crtc - don't set -r by default - nearly identical output in atomic and non-atomic codepaths v2: - Use the crtc->crtc_id, instead of the plane's current crtc_id Signed-off-by: Emil Velikov <emil.velikov@collabora.com> Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com> Tested-by: Ezequiel Garcia <ezequiel@collabora.com>
-rw-r--r--tests/modetest/modetest.c184
1 files changed, 173 insertions, 11 deletions
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 95eab98c..3371eee0 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -1464,10 +1464,120 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
return 0;
}
+static int pipe_attempt_connector(struct device *dev, drmModeConnector *con,
+ struct pipe_arg *pipe)
+{
+ char *con_str;
+ int i;
+
+ con_str = calloc(8, sizeof(char));
+ if (!con_str)
+ return -1;
+
+ sprintf(con_str, "%d", con->connector_id);
+ strcpy(pipe->format_str, "XR24");
+ pipe->fourcc = util_format_fourcc(pipe->format_str);
+ pipe->num_cons = 1;
+ pipe->con_ids = calloc(1, sizeof(*pipe->con_ids));
+ pipe->cons = calloc(1, sizeof(*pipe->cons));
+
+ if (!pipe->con_ids || !pipe->cons)
+ goto free_con_str;
+
+ pipe->con_ids[0] = con->connector_id;
+ pipe->cons[0] = (const char*)con_str;
+
+ pipe->crtc = pipe_find_crtc(dev, pipe);
+ if (!pipe->crtc)
+ goto free_all;
+
+ pipe->crtc_id = pipe->crtc->crtc->crtc_id;
+
+ /* Return the first mode if no preferred. */
+ pipe->mode = &con->modes[0];
+
+ for (i = 0; i < con->count_modes; i++) {
+ drmModeModeInfo *current_mode = &con->modes[i];
+
+ if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
+ pipe->mode = current_mode;
+ break;
+ }
+ }
+
+ sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay);
+
+ return 0;
+
+free_all:
+ free(pipe->cons);
+ free(pipe->con_ids);
+free_con_str:
+ free(con_str);
+ return -1;
+}
+
+static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes)
+{
+ struct pipe_arg *pipes;
+ struct resources *res = dev->resources;
+ drmModeConnector *con = NULL;
+ int i, connected = 0, attempted = 0;
+
+ for (i = 0; i < res->count_connectors; i++) {
+ con = res->connectors[i].connector;
+ if (!con || con->connection != DRM_MODE_CONNECTED)
+ continue;
+ connected++;
+ }
+ if (!connected) {
+ printf("no connected connector!\n");
+ return 0;
+ }
+
+ pipes = calloc(connected, sizeof(struct pipe_arg));
+ if (!pipes)
+ return 0;
+
+ for (i = 0; i < res->count_connectors && attempted < connected; i++) {
+ con = res->connectors[i].connector;
+ if (!con || con->connection != DRM_MODE_CONNECTED)
+ continue;
+
+ if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) {
+ printf("failed fetching preferred mode for connector\n");
+ continue;
+ }
+ attempted++;
+ }
+
+ *out_pipes = pipes;
+ return attempted;
+}
+
+static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc)
+{
+ unsigned int i;
+
+ for (i = 0; i < dev->resources->count_planes; i++) {
+ struct plane *plane = &dev->resources->planes[i];
+ drmModePlane *ovr = plane->plane;
+ if (!ovr)
+ continue;
+
+ // XXX: add is_primary_plane and (?) format checks
+
+ if (ovr->possible_crtcs & get_crtc_mask(dev, crtc))
+ return plane;
+ }
+ return NULL;
+}
+
static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
{
unsigned int i, j;
int ret, x = 0;
+ int preferred = count == 0;
for (i = 0; i < count; i++) {
struct pipe_arg *pipe = &pipes[i];
@@ -1480,6 +1590,16 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
if (ret < 0)
continue;
}
+ if (preferred) {
+ struct pipe_arg *pipe_args;
+
+ count = pipe_find_preferred(dev, &pipe_args);
+ if (!count) {
+ fprintf(stderr, "can't find any preferred connector/mode.\n");
+ return;
+ }
+ pipes = pipe_args;
+ }
if (!dev->use_atomic) {
for (i = 0; i < count; i++) {
@@ -1488,9 +1608,19 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
if (pipe->mode == NULL)
continue;
- dev->mode.width += pipe->mode->hdisplay;
- if (dev->mode.height < pipe->mode->vdisplay)
- dev->mode.height = pipe->mode->vdisplay;
+ if (!preferred) {
+ dev->mode.width += pipe->mode->hdisplay;
+ if (dev->mode.height < pipe->mode->vdisplay)
+ dev->mode.height = pipe->mode->vdisplay;
+ } else {
+ /* XXX: Use a clone mode, more like atomic. We could do per
+ * connector bo/fb, so we don't have the stretched image.
+ */
+ if (dev->mode.width < pipe->mode->hdisplay)
+ dev->mode.width = pipe->mode->hdisplay;
+ if (dev->mode.height < pipe->mode->vdisplay)
+ dev->mode.height = pipe->mode->vdisplay;
+ }
}
if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
@@ -1522,7 +1652,8 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
/* XXX: Actually check if this is needed */
drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0);
- x += pipe->mode->hdisplay;
+ if (!preferred)
+ x += pipe->mode->hdisplay;
if (ret) {
fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
@@ -1534,6 +1665,22 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
add_property(dev, pipe->crtc_id, "MODE_ID", blob_id);
add_property(dev, pipe->crtc_id, "ACTIVE", 1);
+
+ /* By default atomic modeset does not set a primary plane, shrug */
+ if (preferred) {
+ struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc);
+ struct plane_arg plane_args = {
+ .plane_id = plane->plane->plane_id,
+ .crtc_id = pipe->crtc_id,
+ .w = pipe->mode->hdisplay,
+ .h = pipe->mode->vdisplay,
+ .scale = 1.0,
+ .format_str = "XR24",
+ .fourcc = util_format_fourcc(pipe->format_str),
+ };
+
+ atomic_set_planes(dev, &plane_args, 1, false);
+ }
}
}
}
@@ -1858,7 +2005,7 @@ static void parse_fill_patterns(char *arg)
static void usage(char *name)
{
- fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
+ fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name);
fprintf(stderr, "\n Query options:\n\n");
fprintf(stderr, "\t-c\tlist connectors\n");
@@ -1871,6 +2018,7 @@ static void usage(char *name)
fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n");
fprintf(stderr, "\t-C\ttest hw cursor\n");
fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
+ fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n");
fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
fprintf(stderr, "\t-a \tuse atomic API\n");
fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
@@ -1884,7 +2032,7 @@ static void usage(char *name)
exit(0);
}
-static char optstr[] = "acdD:efF:M:P:ps:Cvw:";
+static char optstr[] = "acdD:efF:M:P:ps:Cvrw:";
int main(int argc, char **argv)
{
@@ -1895,6 +2043,7 @@ int main(int argc, char **argv)
int drop_master = 0;
int test_vsync = 0;
int test_cursor = 0;
+ int set_preferred = 0;
int use_atomic = 0;
char *device = NULL;
char *module = NULL;
@@ -1982,6 +2131,9 @@ int main(int argc, char **argv)
case 'v':
test_vsync = 1;
break;
+ case 'r':
+ set_preferred = 1;
+ break;
case 'w':
prop_args = realloc(prop_args,
(prop_count + 1) * sizeof *prop_args);
@@ -2010,6 +2162,15 @@ int main(int argc, char **argv)
fprintf(stderr, "page flipping requires at least one -s option.\n");
return -1;
}
+ if (set_preferred && count) {
+ fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n");
+ return -1;
+ }
+
+ if (set_preferred && plane_count) {
+ fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n");
+ return -1;
+ }
dev.fd = util_open(device, module);
if (dev.fd < 0)
@@ -2046,7 +2207,7 @@ int main(int argc, char **argv)
if (dev.use_atomic) {
dev.req = drmModeAtomicAlloc();
- if (count && plane_count) {
+ if (set_preferred || (count && plane_count)) {
uint64_t cap = 0;
ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
@@ -2055,7 +2216,7 @@ int main(int argc, char **argv)
return 1;
}
- if (count)
+ if (set_preferred || count)
set_mode(&dev, pipe_args, count);
if (plane_count)
@@ -2078,6 +2239,7 @@ int main(int argc, char **argv)
drmModeAtomicFree(dev.req);
dev.req = drmModeAtomicAlloc();
+ /* XXX: properly teardown the preferred mode/plane state */
if (plane_count)
atomic_clear_planes(&dev, plane_args, plane_count);
@@ -2094,7 +2256,7 @@ int main(int argc, char **argv)
drmModeAtomicFree(dev.req);
} else {
- if (count || plane_count) {
+ if (set_preferred || count || plane_count) {
uint64_t cap = 0;
ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
@@ -2103,7 +2265,7 @@ int main(int argc, char **argv)
return 1;
}
- if (count)
+ if (set_preferred || count)
set_mode(&dev, pipe_args, count);
if (plane_count)
@@ -2126,7 +2288,7 @@ int main(int argc, char **argv)
if (plane_count)
clear_planes(&dev, plane_args, plane_count);
- if (count)
+ if (set_preferred || count)
clear_mode(&dev);
}
}