summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRohith Iyer <quic_rohiiyer@quicinc.com>2022-07-25 10:11:41 -0700
committerDmitry Baryshkov <dbaryshkov@gmail.com>2023-09-08 16:27:39 +0000
commit8db39ef7bb119a2fa29e6101b941521c29685c7a (patch)
treee0f78f7ce77b7a777f70e36a82e1aaf73c3dddad
parentee52a88a5723bcd9d505e08e4fadbabb45c66af5 (diff)
modetest: add support for writeback connector
Add writeback support to modetest with the below options: - Passing in -a -c will now also show the writeback connector - Dump the writeback output buffer to bitstream Usage: "./modetest -M msm -s <connector_id>:<widthxheight> -a -o <filepath> -P <plane_id>@<crtc_id>:<widthxheight>+0+0@RG24" This currently supports single writeback connector. Co-developed-by: Rohith Iyer <quic_rohiiyer@quicinc.com> Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com> [DB: dropped custom mode support, fixed segfault] Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
-rw-r--r--tests/modetest/buffers.c19
-rw-r--r--tests/modetest/buffers.h1
-rw-r--r--tests/modetest/modetest.c129
3 files changed, 146 insertions, 3 deletions
diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 0b55aedd..4119f048 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -338,3 +338,22 @@ void bo_destroy(struct bo *bo)
free(bo);
}
+
+void bo_dump(struct bo *bo, const char *filename)
+{
+ FILE *fp;
+
+ if (!bo || !filename)
+ return;
+
+ fp = fopen(filename, "wb");
+ if (fp) {
+ void *addr;
+
+ bo_map(bo, &addr);
+ printf("Dumping buffer %p to file %s.\n", bo->ptr, filename);
+ fwrite(bo->ptr, 1, bo->size, fp);
+ bo_unmap(bo);
+ fclose(fp);
+ }
+}
diff --git a/tests/modetest/buffers.h b/tests/modetest/buffers.h
index 7f95396b..cbd54e9e 100644
--- a/tests/modetest/buffers.h
+++ b/tests/modetest/buffers.h
@@ -36,5 +36,6 @@ struct bo *bo_create(int fd, unsigned int format,
unsigned int handles[4], unsigned int pitches[4],
unsigned int offsets[4], enum util_fill_pattern pattern);
void bo_destroy(struct bo *bo);
+void bo_dump(struct bo *bo, const char *filename);
#endif
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 42e2d1f4..e714818e 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -128,6 +128,7 @@ struct device {
int use_atomic;
drmModeAtomicReq *req;
+ int32_t writeback_fence_fd;
};
static inline int64_t U642I64(uint64_t val)
@@ -811,6 +812,8 @@ struct pipe_arg {
struct crtc *crtc;
unsigned int fb_id[2], current_fb_id;
struct timeval start;
+ unsigned int out_fb_id;
+ struct bo *out_bo;
int swap_count;
};
@@ -1441,6 +1444,24 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
return 0;
}
+static bool pipe_has_writeback_connector(struct device *dev, struct pipe_arg *pipes,
+ unsigned int count)
+{
+ drmModeConnector *connector;
+ unsigned int i, j;
+
+ for (j = 0; j < count; j++) {
+ struct pipe_arg *pipe = &pipes[j];
+
+ for (i = 0; i < pipe->num_cons; i++) {
+ connector = get_connector_by_id(dev, pipe->con_ids[i]);
+ if (connector && connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+ return true;
+ }
+ }
+ return false;
+}
+
static int pipe_attempt_connector(struct device *dev, drmModeConnector *con,
struct pipe_arg *pipe)
{
@@ -1503,7 +1524,8 @@ static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes)
for (i = 0; i < res->count_connectors; i++) {
con = res->connectors[i].connector;
- if (!con || con->connection != DRM_MODE_CONNECTED)
+ if (!con || con->connection != DRM_MODE_CONNECTED ||
+ con->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
continue;
connected++;
}
@@ -1662,6 +1684,75 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
}
}
+static void writeback_config(struct device *dev, struct pipe_arg *pipes, unsigned int count)
+{
+ drmModeConnector *connector;
+ unsigned int i, j;
+
+ for (j = 0; j < count; j++) {
+ struct pipe_arg *pipe = &pipes[j];
+
+ for (i = 0; i < pipe->num_cons; i++) {
+ connector = get_connector_by_id(dev, pipe->con_ids[i]);
+ if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
+ if (!pipe->mode) {
+ fprintf(stderr, "no mode for writeback\n");
+ return;
+ }
+ bo_fb_create(dev->fd, pipes[j].fourcc,
+ pipe->mode->hdisplay, pipe->mode->vdisplay,
+ UTIL_PATTERN_PLAIN,
+ &pipe->out_bo, &pipe->out_fb_id);
+ add_property(dev, pipe->con_ids[i], "WRITEBACK_FB_ID",
+ pipe->out_fb_id);
+ add_property(dev, pipe->con_ids[i], "WRITEBACK_OUT_FENCE_PTR",
+ (uintptr_t)(&dev->writeback_fence_fd));
+ }
+ }
+ }
+}
+
+static int poll_writeback_fence(int fd, int timeout)
+{
+ struct pollfd fds = { fd, POLLIN };
+ int ret;
+
+ do {
+ ret = poll(&fds, 1, timeout);
+ if (ret > 0) {
+ if (fds.revents & (POLLERR | POLLNVAL))
+ return -EINVAL;
+
+ return 0;
+ } else if (ret == 0) {
+ return -ETIMEDOUT;
+ } else {
+ ret = -errno;
+ if (ret == -EINTR || ret == -EAGAIN)
+ continue;
+ return ret;
+ }
+ } while (1);
+
+}
+
+static void dump_output_fb(struct device *dev, struct pipe_arg *pipes, char *dump_path,
+ unsigned int count)
+{
+ drmModeConnector *connector;
+ unsigned int i, j;
+
+ for (j = 0; j < count; j++) {
+ struct pipe_arg *pipe = &pipes[j];
+
+ for (i = 0; i < pipe->num_cons; i++) {
+ connector = get_connector_by_id(dev, pipe->con_ids[i]);
+ if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
+ bo_dump(pipe->out_bo, dump_path);
+ }
+ }
+}
+
static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
{
unsigned int i;
@@ -1990,7 +2081,7 @@ static void parse_fill_patterns(char *arg)
static void usage(char *name)
{
- fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name);
+ fprintf(stderr, "usage: %s [-acDdefMoPpsCvrw]\n", name);
fprintf(stderr, "\n Query options:\n\n");
fprintf(stderr, "\t-c\tlist connectors\n");
@@ -2007,6 +2098,7 @@ static void usage(char *name)
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");
+ fprintf(stderr, "\t-o <desired file path> \t Dump writeback output buffer to file\n");
fprintf(stderr, "\n Generic options:\n\n");
fprintf(stderr, "\t-d\tdrop master after mode set\n");
@@ -2017,7 +2109,7 @@ static void usage(char *name)
exit(0);
}
-static char optstr[] = "acdD:efF:M:P:ps:Cvrw:";
+static char optstr[] = "acdD:efF:M:P:ps:Cvrw:o:";
int main(int argc, char **argv)
{
@@ -2040,6 +2132,7 @@ int main(int argc, char **argv)
struct property_arg *prop_args = NULL;
unsigned int args = 0;
int ret;
+ char *dump_path = NULL;
memset(&dev, 0, sizeof dev);
@@ -2078,6 +2171,9 @@ int main(int argc, char **argv)
/* Preserve the default behaviour of dumping all information. */
args--;
break;
+ case 'o':
+ dump_path = optarg;
+ break;
case 'P':
plane_args = realloc(plane_args,
(plane_count + 1) * sizeof *plane_args);
@@ -2163,6 +2259,7 @@ int main(int argc, char **argv)
if (use_atomic) {
ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
+ drmSetClientCap(dev.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
if (ret) {
fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
drmClose(dev.fd);
@@ -2204,6 +2301,15 @@ int main(int argc, char **argv)
if (set_preferred || count)
set_mode(&dev, pipe_args, count);
+ if (dump_path) {
+ if (!pipe_has_writeback_connector(&dev, pipe_args, count)) {
+ fprintf(stderr, "No writeback connector found, can not dump.\n");
+ return 1;
+ }
+
+ writeback_config(&dev, pipe_args, count);
+ }
+
if (plane_count)
atomic_set_planes(&dev, plane_args, plane_count, false);
@@ -2213,6 +2319,18 @@ int main(int argc, char **argv)
return 1;
}
+ /*
+ * Since only writeback connectors have an output fb, this should only be
+ * called for writeback.
+ */
+ if (dump_path) {
+ ret = poll_writeback_fence(dev.writeback_fence_fd, 1000);
+ if (ret)
+ fprintf(stderr, "Poll for writeback error: %d. Skipping Dump.\n",
+ ret);
+ dump_output_fb(&dev, pipe_args, dump_path, count);
+ }
+
if (test_vsync)
atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count);
@@ -2241,6 +2359,11 @@ int main(int argc, char **argv)
drmModeAtomicFree(dev.req);
} else {
+ if (dump_path) {
+ fprintf(stderr, "writeback / dump is only supported in atomic mode\n");
+ return 1;
+ }
+
if (set_preferred || count || plane_count) {
uint64_t cap = 0;