Modetest gets the property name from user to set it. So the name must be converted to its id. Until now, this is done in the set_property(). But to support atomic modeset in modetest, this logic should be separated from the fuction, because atomic modeset and legacy modeset use different IOCTLs.
Signed-off-by: Hyungwon Hwang human.hwang@samsung.com --- tests/modetest/modetest.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 3b01918..08ecf58 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -894,12 +894,11 @@ struct property_arg { uint64_t value; };
-static void set_property(struct device *dev, struct property_arg *p) +static int get_prop_info(struct resources *resources, struct property_arg *p, + const char *obj_type) { drmModeObjectProperties *props = NULL; drmModePropertyRes **props_info = NULL; - const char *obj_type; - int ret; int i;
p->obj_type = 0; @@ -918,21 +917,21 @@ static void set_property(struct device *dev, struct property_arg *p) } \ } while(0) \
- find_object(dev->resources, res, crtc, CRTC); + find_object(resources, res, crtc, CRTC); if (p->obj_type == 0) - find_object(dev->resources, res, connector, CONNECTOR); + find_object(resources, res, connector, CONNECTOR); if (p->obj_type == 0) - find_object(dev->resources, plane_res, plane, PLANE); + find_object(resources, plane_res, plane, PLANE); if (p->obj_type == 0) { fprintf(stderr, "Object %i not found, can't set property\n", p->obj_id); - return; + return -1; }
if (!props) { fprintf(stderr, "%s %i has no properties\n", obj_type, p->obj_id); - return; + return -1; }
for (i = 0; i < (int)props->count_props; ++i) { @@ -945,11 +944,23 @@ static void set_property(struct device *dev, struct property_arg *p) if (i == (int)props->count_props) { fprintf(stderr, "%s %i has no %s property\n", obj_type, p->obj_id, p->name); - return; + return -1; }
p->prop_id = props->props[i];
+ return 0; +} + +static void set_property(struct device *dev, struct property_arg *p) +{ + int ret; + const char *obj_type = NULL; + + ret = get_prop_info(dev->resources, p, obj_type); + if (ret < 0) + return; + ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, p->prop_id, p->value); if (ret < 0) -- 2.4.3
This patch adds support for atomic modeset. Using -a option, user can make modeset to use DRM_IOCTL_MODE_ATOMIC instead of legacy IOCTLs. Also, by using -w option, user can set the property as before.
Signed-off-by: Hyungwon Hwang human.hwang@samsung.com --- tests/modetest/modetest.c | 273 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 8 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 08ecf58..bc5a227 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -1477,25 +1477,32 @@ static int parse_property(struct property_arg *p, const char *arg)
static void usage(char *name) { - fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name); + fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name); + fprintf(stderr, "\tA: supported in atomic modeset\n"); + fprintf(stderr, "\tL: supported in legacy modeset\n");
- fprintf(stderr, "\n Query options:\n\n"); + fprintf(stderr, "\n Query options: [AL]\n\n"); fprintf(stderr, "\t-c\tlist connectors\n"); fprintf(stderr, "\t-e\tlist encoders\n"); fprintf(stderr, "\t-f\tlist framebuffers\n"); fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
- fprintf(stderr, "\n Test options:\n\n"); + fprintf(stderr, "\n Common Test options: [AL]\n\n"); + fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); + + fprintf(stderr, "\n Atomic Test options: [A]\n\n"); + fprintf(stderr, "\t-a\tuse atomic modeset\n"); + + fprintf(stderr, "\n Legacy test options: [L]\n\n"); fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<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-w <obj_id>:<prop_name>:<value>\tset property\n");
fprintf(stderr, "\n Generic options:\n\n"); - fprintf(stderr, "\t-d\tdrop master after mode set\n"); - fprintf(stderr, "\t-M module\tuse the given driver\n"); - fprintf(stderr, "\t-D device\tuse the given device\n"); + fprintf(stderr, "\t-d\tdrop master after mode set [L]\n"); + fprintf(stderr, "\t-M module\tuse the given driver [AL]\n"); + fprintf(stderr, "\t-D device\tuse the given device [AL]\n");
fprintf(stderr, "\n\tDefault is to dump all info.\n"); exit(0); @@ -1554,7 +1561,224 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) return 0; }
-static char optstr[] = "cdD:efM:P:ps:Cvw:"; +static bool is_obj_id_in_prop_args(struct property_arg *prop_args, + unsigned int prop_count, uint32_t obj_id) +{ + unsigned int i; + + for (i = 0; i < prop_count; i++) + if (obj_id == prop_args[i].obj_id) + return true; + + return false; +} + +static int get_value_in_prop_args(struct property_arg *prop_args, + unsigned int prop_count, uint32_t obj_id, + const char *name, uint64_t *out) +{ + unsigned int i; + + for (i = 0; i < prop_count; i++) { + if (prop_args[i].obj_id == obj_id && + !strcmp(prop_args[i].name, name)) { + *out = prop_args[i].value; + return 0; + } + } + + return -1; +} + +static uint32_t get_plane_prop_id(struct resources *res, uint32_t obj_id, + const char *name) +{ + drmModePropertyRes *props_info; + struct plane *plane; + unsigned int i, j; + + for (i = 0; i < res->plane_res->count_planes; i++) { + plane = &res->planes[i]; + if (plane->plane->plane_id != obj_id) + continue; + + for (j = 0; j < plane->props->count_props; j++) { + props_info = plane->props_info[j]; + if (!strcmp(props_info->name, name)) + return props_info->prop_id; + } + } + + return 0; +} + +static int allocate_fb(int fd, drmModeAtomicReqPtr req, struct resources *res, + uint32_t width, uint32_t height, uint32_t pixel_format, + int pattern, struct bo **bo, uint32_t *fb_id) +{ + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + int ret; + + *bo = bo_create(fd, pixel_format, width, height, + handles, pitches, offsets, pattern); + if (*bo == NULL) { + fprintf(stderr, "failed to create bo (%ux%u): %s\n", + width, height, strerror(errno)); + return -1; + } + + ret = drmModeAddFB2(fd, width, height, pixel_format, + handles, pitches, offsets, fb_id, 0); + if (ret) { + fprintf(stderr, "failed to add fb (%ux%u): %s\n", + width, height, strerror(errno)); + bo_destroy(*bo); + return ret; + } + + return 0; +} + +static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req, + struct resources *res, struct property_arg *prop_args, + unsigned int prop_count, struct bo **bo, uint32_t *fb_id) +{ + uint32_t plane_id, fb_obj_id, pixel_format; + uint64_t width, height; + int ret = 0, i; + + for (i = 0; i < (int)res->plane_res->count_planes; i++) { + plane_id = res->planes[i].plane->plane_id; + if (!is_obj_id_in_prop_args(prop_args, prop_count, plane_id)) + continue; + + fb_obj_id = get_plane_prop_id(res, plane_id, "FB_ID"); + if (!fb_obj_id) { + fprintf(stderr, "plane(%u) does not exist\n", plane_id); + goto err; + } + + ret = get_value_in_prop_args(prop_args, prop_count, plane_id, + "SRC_W", &width); + if (ret < 0) { + fprintf(stderr, "SRC_W for plane (%u) must be set\n", plane_id); + goto err; + } + + ret = get_value_in_prop_args(prop_args, prop_count, plane_id, + "SRC_H", &height); + if (ret < 0) { + fprintf(stderr, "SRC_H for plane (%u) must be set\n", plane_id); + goto err; + } + + pixel_format = DRM_FORMAT_XRGB8888; + + ret = allocate_fb(dev->fd, req, res, width, height, pixel_format, + PATTERN_SMPTE, &bo[i], &fb_id[i]); + if (ret < 0) + goto err; + + ret = drmModeAtomicAddProperty(req, plane_id, fb_obj_id, fb_id[i]); + if (ret < 0) { + fprintf(stderr, "failed to add atomic property for atomic modeset\n"); + goto err; + } + } + + return 0; + +err: + while (i > -1) { + if (!fb_id[i]) + continue; + + drmModeRmFB(dev->fd, fb_id[i]); + bo_destroy(bo[i]); + i--; + } + + return ret; +} + +static void deallocate_fbs(int fd, int num_planes, uint32_t *fb_id, struct bo **bo) +{ + int i; + + for (i = 0; i < num_planes; i++) { + if (!fb_id[i]) + continue; + + drmModeRmFB(fd, fb_id[i]); + bo_destroy(bo[i]); + } +} + +static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, + struct property_arg *prop_args, unsigned int prop_count) +{ + unsigned int num_planes; + const char *obj_type = NULL; + uint32_t flags = 0; + uint32_t *fb_id; + struct bo **bo; + int ret, i; + + for (i = 0; (unsigned int)i < prop_count; ++i) { + ret = get_prop_info(dev->resources, &prop_args[i], obj_type); + if (ret < 0) + return ret; + + ret = drmModeAtomicAddProperty(req, prop_args[i].obj_id, + prop_args[i].prop_id, prop_args[i].value); + if (ret < 0) { + fprintf(stderr, "failed to add property for atomic modeset (%d)\n", + ret); + return ret; + } + } + + num_planes = dev->resources->plane_res->count_planes; + + bo = calloc(num_planes, sizeof(*bo)); + if (!bo) { + fprintf(stderr, "failed to allocate memory fo bo array\n"); + return -1; + } + + fb_id = calloc(num_planes, sizeof(*fb_id)); + if (!fb_id) { + fprintf(stderr, "failed to allocate memory fo fb_id array\n"); + free(bo); + return -1; + } + + ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo, fb_id); + if (ret < 0) { + free(fb_id); + free(bo); + return ret; + } + + ret = drmModeAtomicCommit(dev->fd, req, flags, NULL); + if (ret < 0) { + fprintf(stderr, "failed to commit for atomic modeset\n"); + deallocate_fbs(dev->fd, num_planes, fb_id, bo); + free(fb_id); + free(bo); + return ret; + } + + getchar(); + + deallocate_fbs(dev->fd, num_planes, fb_id, bo); + free(fb_id); + free(bo); + + return 0; +} + +static char optstr[] = "acdD:efM:P:ps:Cvw:";
int main(int argc, char **argv) { @@ -1574,6 +1798,8 @@ int main(int argc, char **argv) struct pipe_arg *pipe_args = NULL; struct plane_arg *plane_args = NULL; struct property_arg *prop_args = NULL; + drmModeAtomicReqPtr req = NULL; + bool is_atomic = false; unsigned int args = 0; int ret;
@@ -1584,6 +1810,10 @@ int main(int argc, char **argv) args++;
switch (c) { + case 'a': + is_atomic = true; + args--; + break; case 'c': connectors = 1; break; @@ -1705,6 +1935,22 @@ int main(int argc, char **argv) return -1; }
+ if (is_atomic) { + req = drmModeAtomicAlloc(); + if (req == NULL) { + fprintf(stderr, "failed to allocate drmModeAtomicReqPtr\n"); + return 1; + } + + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + fprintf(stderr, "Kernel DRM driver is not capable of atomic modeset\n"); + drmModeAtomicFree(req); + + return 1; + } + } + dev.resources = get_resources(&dev); if (!dev.resources) { drmClose(dev.fd); @@ -1727,6 +1973,17 @@ int main(int argc, char **argv) dump_resource(&dev, planes); dump_resource(&dev, framebuffers);
+ if (is_atomic) { + ret = atomic_modeset(&dev, req, prop_args, prop_count); + if (ret < 0) + fprintf(stderr, "failed to atomic modeset (%s)\n", + strerror(errno)); + + free_resources(dev.resources); + drmModeAtomicFree(req); + return ret; + } + for (i = 0; i < prop_count; ++i) set_property(&dev, &prop_args[i]);
-- 2.4.3
On 23 September 2015 at 03:45, Hyungwon Hwang human.hwang@samsung.com wrote:
This patch adds support for atomic modeset. Using -a option, user can make modeset to use DRM_IOCTL_MODE_ATOMIC instead of legacy IOCTLs. Also, by using -w option, user can set the property as before.
Signed-off-by: Hyungwon Hwang human.hwang@samsung.com
tests/modetest/modetest.c | 273 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 8 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 08ecf58..bc5a227 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -1477,25 +1477,32 @@ static int parse_property(struct property_arg *p, const char *arg)
static void usage(char *name) {
fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name);
fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
fprintf(stderr, "\tA: supported in atomic modeset\n");
fprintf(stderr, "\tL: supported in legacy modeset\n");
fprintf(stderr, "\n Query options:\n\n");
fprintf(stderr, "\n Query options: [AL]\n\n"); fprintf(stderr, "\t-c\tlist connectors\n"); fprintf(stderr, "\t-e\tlist encoders\n"); fprintf(stderr, "\t-f\tlist framebuffers\n"); fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
fprintf(stderr, "\n Test options:\n\n");
fprintf(stderr, "\n Common Test options: [AL]\n\n");
fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
fprintf(stderr, "\n Atomic Test options: [A]\n\n");
fprintf(stderr, "\t-a\tuse atomic modeset\n");
fprintf(stderr, "\n Legacy test options: [L]\n\n"); fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<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-w <obj_id>:<prop_name>:<value>\tset property\n"); fprintf(stderr, "\n Generic options:\n\n");
fprintf(stderr, "\t-d\tdrop master after mode set\n");
fprintf(stderr, "\t-M module\tuse the given driver\n");
fprintf(stderr, "\t-D device\tuse the given device\n");
fprintf(stderr, "\t-d\tdrop master after mode set [L]\n");
fprintf(stderr, "\t-M module\tuse the given driver [AL]\n");
fprintf(stderr, "\t-D device\tuse the given device [AL]\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); exit(0);
@@ -1554,7 +1561,224 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) return 0; }
-static char optstr[] = "cdD:efM:P:ps:Cvw:"; +static bool is_obj_id_in_prop_args(struct property_arg *prop_args,
const struct
unsigned int prop_count, uint32_t obj_id)
+{
unsigned int i;
for (i = 0; i < prop_count; i++)
if (obj_id == prop_args[i].obj_id)
return true;
return false;
+}
+static int get_value_in_prop_args(struct property_arg *prop_args,
Ditto
unsigned int prop_count, uint32_t obj_id,
const char *name, uint64_t *out)
+{
unsigned int i;
for (i = 0; i < prop_count; i++) {
if (prop_args[i].obj_id == obj_id &&
!strcmp(prop_args[i].name, name)) {
*out = prop_args[i].value;
return 0;
}
}
return -1;
+}
+static uint32_t get_plane_prop_id(struct resources *res, uint32_t obj_id,
Ditto
const char *name)
+{
drmModePropertyRes *props_info;
struct plane *plane;
unsigned int i, j;
for (i = 0; i < res->plane_res->count_planes; i++) {
plane = &res->planes[i];
if (plane->plane->plane_id != obj_id)
continue;
for (j = 0; j < plane->props->count_props; j++) {
props_info = plane->props_info[j];
if (!strcmp(props_info->name, name))
return props_info->prop_id;
}
}
return 0;
+}
+static int allocate_fb(int fd, drmModeAtomicReqPtr req, struct resources *res,
req and res are unused.
uint32_t width, uint32_t height, uint32_t pixel_format,
int pattern, struct bo **bo, uint32_t *fb_id)
+{
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
int ret;
*bo = bo_create(fd, pixel_format, width, height,
handles, pitches, offsets, pattern);
if (*bo == NULL) {
fprintf(stderr, "failed to create bo (%ux%u): %s\n",
width, height, strerror(errno));
return -1;
}
ret = drmModeAddFB2(fd, width, height, pixel_format,
handles, pitches, offsets, fb_id, 0);
if (ret) {
fprintf(stderr, "failed to add fb (%ux%u): %s\n",
width, height, strerror(errno));
bo_destroy(*bo);
return ret;
}
return 0;
+}
+static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req,
struct resources *res, struct property_arg *prop_args,
Constify res and prop_args ?
unsigned int prop_count, struct bo **bo, uint32_t *fb_id)
+{
uint32_t plane_id, fb_obj_id, pixel_format;
uint64_t width, height;
int ret = 0, i;
for (i = 0; i < (int)res->plane_res->count_planes; i++) {
Define i as unsigned, drop the cast and ...
plane_id = res->planes[i].plane->plane_id;
if (!is_obj_id_in_prop_args(prop_args, prop_count, plane_id))
continue;
fb_obj_id = get_plane_prop_id(res, plane_id, "FB_ID");
if (!fb_obj_id) {
fprintf(stderr, "plane(%u) does not exist\n", plane_id);
goto err;
}
ret = get_value_in_prop_args(prop_args, prop_count, plane_id,
"SRC_W", &width);
if (ret < 0) {
fprintf(stderr, "SRC_W for plane (%u) must be set\n", plane_id);
goto err;
}
ret = get_value_in_prop_args(prop_args, prop_count, plane_id,
"SRC_H", &height);
if (ret < 0) {
fprintf(stderr, "SRC_H for plane (%u) must be set\n", plane_id);
goto err;
}
pixel_format = DRM_FORMAT_XRGB8888;
ret = allocate_fb(dev->fd, req, res, width, height, pixel_format,
PATTERN_SMPTE, &bo[i], &fb_id[i]);
if (ret < 0)
goto err;
ret = drmModeAtomicAddProperty(req, plane_id, fb_obj_id, fb_id[i]);
if (ret < 0) {
fprintf(stderr, "failed to add atomic property for atomic modeset\n");
goto err;
}
}
return 0;
+err:
while (i > -1) {
... then use while (i--) {
if (!fb_id[i])
continue;
drmModeRmFB(dev->fd, fb_id[i]);
bo_destroy(bo[i]);
i--;
and drop this line.
}
return ret;
+}
+static void deallocate_fbs(int fd, int num_planes, uint32_t *fb_id, struct bo **bo) +{
int i;
Make both i and num_planes unsigned ?
for (i = 0; i < num_planes; i++) {
if (!fb_id[i])
continue;
drmModeRmFB(fd, fb_id[i]);
bo_destroy(bo[i]);
Shove the contents of the loop into deallocate_fb() to complement allocate_fb() and use it here + allocate_fbs() error path ?
}
+}
+static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req,
struct property_arg *prop_args, unsigned int prop_count)
+{
unsigned int num_planes;
const char *obj_type = NULL;
You don't need this.
uint32_t flags = 0;
And you can use 0 directly where needed.
uint32_t *fb_id;
struct bo **bo;
int ret, i;
for (i = 0; (unsigned int)i < prop_count; ++i) {
Why is i signed int ?
ret = get_prop_info(dev->resources, &prop_args[i], obj_type);
if (ret < 0)
return ret;
ret = drmModeAtomicAddProperty(req, prop_args[i].obj_id,
prop_args[i].prop_id, prop_args[i].value);
if (ret < 0) {
Perhaps we should unwind all the state that we've accumulated (same goes for the remaining error paths in this func), although I might be pushing my luck with your patience.
fprintf(stderr, "failed to add property for atomic modeset (%d)\n",
ret);
return ret;
}
}
num_planes = dev->resources->plane_res->count_planes;
bo = calloc(num_planes, sizeof(*bo));
if (!bo) {
fprintf(stderr, "failed to allocate memory fo bo array\n");
return -1;
}
fb_id = calloc(num_planes, sizeof(*fb_id));
if (!fb_id) {
fprintf(stderr, "failed to allocate memory fo fb_id array\n");
free(bo);
return -1;
}
ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo, fb_id);
if (ret < 0) {
free(fb_id);
free(bo);
return ret;
}
ret = drmModeAtomicCommit(dev->fd, req, flags, NULL);
if (ret < 0) {
fprintf(stderr, "failed to commit for atomic modeset\n");
Use labels rather than the ever increasing teardown ?
deallocate_fbs(dev->fd, num_planes, fb_id, bo);
free(fb_id);
free(bo);
return ret;
}
getchar();
deallocate_fbs(dev->fd, num_planes, fb_id, bo);
free(fb_id);
free(bo);
return 0;
+}
+static char optstr[] = "acdD:efM:P:ps:Cvw:";
int main(int argc, char **argv) { @@ -1574,6 +1798,8 @@ int main(int argc, char **argv) struct pipe_arg *pipe_args = NULL; struct plane_arg *plane_args = NULL; struct property_arg *prop_args = NULL;
drmModeAtomicReqPtr req = NULL;
Initialisation isn't needed.
-Emil
This patch adds support for atomic page flip. User can specify -V option with the plane id for testing atomic page flipping.
Signed-off-by: Hyungwon Hwang human.hwang@samsung.com --- tests/modetest/modetest.c | 195 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 8 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index bc5a227..418acaa 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -747,6 +747,10 @@ struct pipe_arg { struct timeval start;
int swap_count; + + /* for atomic modeset */ + uint32_t plane_id; + uint32_t fb_obj_id; };
struct plane_arg { @@ -1477,7 +1481,7 @@ static int parse_property(struct property_arg *p, const char *arg)
static void usage(char *name) { - fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name); + fprintf(stderr, "usage: %s [-acDdefMPpsCvVw]\n", name); fprintf(stderr, "\tA: supported in atomic modeset\n"); fprintf(stderr, "\tL: supported in legacy modeset\n");
@@ -1492,6 +1496,7 @@ static void usage(char *name)
fprintf(stderr, "\n Atomic Test options: [A]\n\n"); fprintf(stderr, "\t-a\tuse atomic modeset\n"); + fprintf(stderr, "\t-V <flipping_plane_id>\ttest vsynced page flipping\n");
fprintf(stderr, "\n Legacy test options: [L]\n\n"); fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); @@ -1641,7 +1646,8 @@ static int allocate_fb(int fd, drmModeAtomicReqPtr req, struct resources *res,
static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req, struct resources *res, struct property_arg *prop_args, - unsigned int prop_count, struct bo **bo, uint32_t *fb_id) + unsigned int prop_count, struct bo **bo, uint32_t *fb_id, + uint32_t flip_plane_id) { uint32_t plane_id, fb_obj_id, pixel_format; uint64_t width, height; @@ -1652,6 +1658,9 @@ static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req, if (!is_obj_id_in_prop_args(prop_args, prop_count, plane_id)) continue;
+ if (flip_plane_id == plane_id) + dev->mode.fb_id = fb_id[i]; + fb_obj_id = get_plane_prop_id(res, plane_id, "FB_ID"); if (!fb_obj_id) { fprintf(stderr, "plane(%u) does not exist\n", plane_id); @@ -1714,8 +1723,162 @@ static void deallocate_fbs(int fd, int num_planes, uint32_t *fb_id, struct bo ** } }
+static void atomic_page_flip_handler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *data) +{ + static drmModeAtomicReqPtr req = NULL; + unsigned int new_fb_id; + struct timeval end; + struct pipe_arg *pipe; + double t; + uint32_t flags = 0; + int ret; + + pipe = (struct pipe_arg *)(unsigned long)data; + + req = drmModeAtomicAlloc(); + if (!req) { + fprintf(stderr, "failed to allocate drmModeAtomicReqPtr\n"); + return; + } + + if (pipe->current_fb_id == pipe->fb_id[0]) + new_fb_id = pipe->fb_id[1]; + else + new_fb_id = pipe->fb_id[0]; + + pipe->current_fb_id = new_fb_id; + pipe->swap_count++; + + ret = drmModeAtomicAddProperty(req, pipe->plane_id, pipe->fb_obj_id, new_fb_id); + if (ret < 0) { + fprintf(stderr, "failed to add atomic property in pageflip handler\n"); + drmModeAtomicFree(req); + return; + } + + flags = DRM_MODE_PAGE_FLIP_EVENT; + ret = drmModeAtomicCommit(fd, req, flags, pipe); + if (ret < 0) { + fprintf(stderr, "failed to commit in pageflip handler\n"); + drmModeAtomicFree(req); + return; + } + + if (pipe->swap_count == 60) { + gettimeofday(&end, NULL); + t = end.tv_sec + end.tv_usec * 1e-6 - + (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); + fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); + pipe->swap_count = 0; + pipe->start = end; + } + + drmModeAtomicFree(req); +} + +static void atomic_test_page_flip(struct device *dev, drmModeAtomicReqPtr req, + struct resources *res, struct property_arg *prop_args, + unsigned int prop_count, unsigned int flip_plane_id) +{ + struct bo *other_bo; + unsigned int other_fb_id; + struct pipe_arg pipe; + drmEventContext evctx; + uint32_t flags = 0, fb_obj_id = 0, pixel_format; + uint64_t width, height; + int ret; + + fb_obj_id = get_plane_prop_id(res, flip_plane_id, "FB_ID"); + if (!fb_obj_id) { + fprintf(stderr, "plane(%u) does not exist\n", flip_plane_id); + return; + } + + if (!is_obj_id_in_prop_args(prop_args, prop_count, flip_plane_id)) { + fprintf(stderr, "plane (%u) must be set for pageflip\n", flip_plane_id); + return; + } + + ret = get_value_in_prop_args(prop_args, prop_count, flip_plane_id, + "SRC_W", &width); + if (ret < 0) { + fprintf(stderr, "SRC_W for plane (%u) must be set\n", flip_plane_id); + return; + } + + ret = get_value_in_prop_args(prop_args, prop_count, flip_plane_id, + "SRC_H", &height); + if (ret < 0) { + fprintf(stderr, "SRC_H for plane (%u) must be set\n", flip_plane_id); + return; + } + + pixel_format = DRM_FORMAT_XRGB8888; + + ret = allocate_fb(dev->fd, req, res, width, height, pixel_format, + PATTERN_TILES, &other_bo, &other_fb_id); + if (ret < 0) + return; + + ret = drmModeAtomicAddProperty(req, flip_plane_id, fb_obj_id, + other_fb_id); + if (ret < 0) { + fprintf(stderr, "failed to add atomic property for pageflip"); + goto err; + } + + gettimeofday(&pipe.start, NULL); + pipe.swap_count = 0; + pipe.plane_id = flip_plane_id; + pipe.fb_obj_id = fb_obj_id; + pipe.fb_id[0] = dev->mode.fb_id; + pipe.fb_id[1] = other_fb_id; + pipe.current_fb_id = other_fb_id; + + flags = DRM_MODE_PAGE_FLIP_EVENT; + + ret = drmModeAtomicCommit(dev->fd, req, flags, &pipe); + if (ret < 0) { + fprintf(stderr, "failed to commit for pageflip\n"); + goto err; + } + + memset(&evctx, 0, sizeof evctx); + evctx.version = 2; + evctx.vblank_handler = NULL; + evctx.page_flip_handler = atomic_page_flip_handler; + + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(dev->fd, &fds); + ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + drmHandleEvent(dev->fd, &evctx); + } + +err: + drmModeRmFB(dev->fd, other_fb_id); + bo_destroy(other_bo); + + return; +} + static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, - struct property_arg *prop_args, unsigned int prop_count) + struct property_arg *prop_args, unsigned int prop_count, + int test_vsync, int flip_plane_id) { unsigned int num_planes; const char *obj_type = NULL; @@ -1753,7 +1916,8 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return -1; }
- ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo, fb_id); + ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo, + fb_id, flip_plane_id); if (ret < 0) { free(fb_id); free(bo); @@ -1769,6 +1933,10 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return ret; }
+ if (test_vsync) + atomic_test_page_flip(dev, req, dev->resources, + prop_args, prop_count, flip_plane_id); + getchar();
deallocate_fbs(dev->fd, num_planes, fb_id, bo); @@ -1778,7 +1946,7 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return 0; }
-static char optstr[] = "acdD:efM:P:ps:Cvw:"; +static char optstr[] = "acdD:efM:P:ps:CvV:w:";
int main(int argc, char **argv) { @@ -1792,7 +1960,7 @@ int main(int argc, char **argv) const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc", "msm", "sti", "tegra", "imx-drm", "rockchip", "atmel-hlcdc" }; char *device = NULL; char *module = NULL; - unsigned int i; + unsigned int i, flip_plane_id = 0; unsigned int count = 0, plane_count = 0; unsigned int prop_count = 0; struct pipe_arg *pipe_args = NULL; @@ -1873,6 +2041,11 @@ int main(int argc, char **argv) case 'v': test_vsync = 1; break; + case 'V': + if (sscanf(optarg, "%u", &flip_plane_id) != 1) + usage(argv[0]); + test_vsync = 1; + break; case 'w': prop_args = realloc(prop_args, (prop_count + 1) * sizeof *prop_args); @@ -1925,11 +2098,16 @@ int main(int argc, char **argv) return -1; }
- if (test_vsync && !count) { + if (test_vsync && (!count && !is_atomic)) { fprintf(stderr, "page flipping requires at least one -s option.\n"); return -1; }
+ if (test_vsync && is_atomic && flip_plane_id == 0) { + fprintf(stderr, "fliping plane id must be set for atomic pageflip\n"); + return -1; + } + if (test_cursor && !cursor_supported()) { fprintf(stderr, "hw cursor not supported by drm.\n"); return -1; @@ -1974,7 +2152,8 @@ int main(int argc, char **argv) dump_resource(&dev, framebuffers);
if (is_atomic) { - ret = atomic_modeset(&dev, req, prop_args, prop_count); + ret = atomic_modeset(&dev, req, prop_args, prop_count, + test_vsync, flip_plane_id); if (ret < 0) fprintf(stderr, "failed to atomic modeset (%s)\n", strerror(errno));
On 23 September 2015 at 03:45, Hyungwon Hwang human.hwang@samsung.com wrote:
This patch adds support for atomic page flip. User can specify -V option with the plane id for testing atomic page flipping.
Signed-off-by: Hyungwon Hwang human.hwang@samsung.com
tests/modetest/modetest.c | 195 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 187 insertions(+), 8 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index bc5a227..418acaa 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -747,6 +747,10 @@ struct pipe_arg { struct timeval start;
int swap_count;
/* for atomic modeset */
uint32_t plane_id;
uint32_t fb_obj_id;
};
struct plane_arg { @@ -1477,7 +1481,7 @@ static int parse_property(struct property_arg *p, const char *arg)
static void usage(char *name) {
fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
fprintf(stderr, "usage: %s [-acDdefMPpsCvVw]\n", name); fprintf(stderr, "\tA: supported in atomic modeset\n"); fprintf(stderr, "\tL: supported in legacy modeset\n");
@@ -1492,6 +1496,7 @@ static void usage(char *name)
fprintf(stderr, "\n Atomic Test options: [A]\n\n"); fprintf(stderr, "\t-a\tuse atomic modeset\n");
fprintf(stderr, "\t-V <flipping_plane_id>\ttest vsynced page flipping\n"); fprintf(stderr, "\n Legacy test options: [L]\n\n"); fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
@@ -1641,7 +1646,8 @@ static int allocate_fb(int fd, drmModeAtomicReqPtr req, struct resources *res,
static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req, struct resources *res, struct property_arg *prop_args,
unsigned int prop_count, struct bo **bo, uint32_t *fb_id)
unsigned int prop_count, struct bo **bo, uint32_t *fb_id,
uint32_t flip_plane_id)
{ uint32_t plane_id, fb_obj_id, pixel_format; uint64_t width, height; @@ -1652,6 +1658,9 @@ static int allocate_fbs(struct device *dev, drmModeAtomicReqPtr req, if (!is_obj_id_in_prop_args(prop_args, prop_count, plane_id)) continue;
if (flip_plane_id == plane_id)
dev->mode.fb_id = fb_id[i];
fb_obj_id = get_plane_prop_id(res, plane_id, "FB_ID"); if (!fb_obj_id) { fprintf(stderr, "plane(%u) does not exist\n", plane_id);
@@ -1714,8 +1723,162 @@ static void deallocate_fbs(int fd, int num_planes, uint32_t *fb_id, struct bo ** } }
+static void atomic_page_flip_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, void *data)
+{
static drmModeAtomicReqPtr req = NULL;
Initialisation not needed
unsigned int new_fb_id;
struct timeval end;
struct pipe_arg *pipe;
double t;
uint32_t flags = 0;
Feed 0 directly into the function ?
int ret;
pipe = (struct pipe_arg *)(unsigned long)data;
req = drmModeAtomicAlloc();
if (!req) {
fprintf(stderr, "failed to allocate drmModeAtomicReqPtr\n");
return;
}
if (pipe->current_fb_id == pipe->fb_id[0])
new_fb_id = pipe->fb_id[1];
else
new_fb_id = pipe->fb_id[0];
pipe->current_fb_id = new_fb_id;
pipe->swap_count++;
ret = drmModeAtomicAddProperty(req, pipe->plane_id, pipe->fb_obj_id, new_fb_id);
if (ret < 0) {
fprintf(stderr, "failed to add atomic property in pageflip handler\n");
Use a goto label ?
drmModeAtomicFree(req);
return;
}
flags = DRM_MODE_PAGE_FLIP_EVENT;
ret = drmModeAtomicCommit(fd, req, flags, pipe);
if (ret < 0) {
fprintf(stderr, "failed to commit in pageflip handler\n");
drmModeAtomicFree(req);
return;
}
if (pipe->swap_count == 60) {
Use vrefresh here ?
gettimeofday(&end, NULL);
t = end.tv_sec + end.tv_usec * 1e-6 -
(pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
pipe->swap_count = 0;
pipe->start = end;
}
drmModeAtomicFree(req);
+}
+static void atomic_test_page_flip(struct device *dev, drmModeAtomicReqPtr req,
struct resources *res, struct property_arg *prop_args,
constify the structs ?
unsigned int prop_count, unsigned int flip_plane_id)
+{
struct bo *other_bo;
unsigned int other_fb_id;
struct pipe_arg pipe;
drmEventContext evctx;
uint32_t flags = 0, fb_obj_id = 0, pixel_format;
Variable and initialisation isn't needed.
uint64_t width, height;
int ret;
fb_obj_id = get_plane_prop_id(res, flip_plane_id, "FB_ID");
if (!fb_obj_id) {
fprintf(stderr, "plane(%u) does not exist\n", flip_plane_id);
return;
}
if (!is_obj_id_in_prop_args(prop_args, prop_count, flip_plane_id)) {
fprintf(stderr, "plane (%u) must be set for pageflip\n", flip_plane_id);
return;
}
ret = get_value_in_prop_args(prop_args, prop_count, flip_plane_id,
"SRC_W", &width);
if (ret < 0) {
fprintf(stderr, "SRC_W for plane (%u) must be set\n", flip_plane_id);
return;
}
ret = get_value_in_prop_args(prop_args, prop_count, flip_plane_id,
"SRC_H", &height);
if (ret < 0) {
fprintf(stderr, "SRC_H for plane (%u) must be set\n", flip_plane_id);
return;
}
pixel_format = DRM_FORMAT_XRGB8888;
ret = allocate_fb(dev->fd, req, res, width, height, pixel_format,
PATTERN_TILES, &other_bo, &other_fb_id);
if (ret < 0)
return;
ret = drmModeAtomicAddProperty(req, flip_plane_id, fb_obj_id,
other_fb_id);
if (ret < 0) {
fprintf(stderr, "failed to add atomic property for pageflip");
goto err;
}
gettimeofday(&pipe.start, NULL);
pipe.swap_count = 0;
pipe.plane_id = flip_plane_id;
pipe.fb_obj_id = fb_obj_id;
pipe.fb_id[0] = dev->mode.fb_id;
pipe.fb_id[1] = other_fb_id;
pipe.current_fb_id = other_fb_id;
flags = DRM_MODE_PAGE_FLIP_EVENT;
ret = drmModeAtomicCommit(dev->fd, req, flags, &pipe);
if (ret < 0) {
fprintf(stderr, "failed to commit for pageflip\n");
goto err;
}
memset(&evctx, 0, sizeof evctx);
evctx.version = 2;
evctx.vblank_handler = NULL;
evctx.page_flip_handler = atomic_page_flip_handler;
while (1) {
struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(dev->fd, &fds);
ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
if (ret <= 0) {
fprintf(stderr, "select timed out or error (ret %d)\n",
ret);
continue;
} else if (FD_ISSET(0, &fds)) {
break;
}
drmHandleEvent(dev->fd, &evctx);
}
+err:
drmModeRmFB(dev->fd, other_fb_id);
bo_destroy(other_bo);
return;
+}
static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req,
struct property_arg *prop_args, unsigned int prop_count)
struct property_arg *prop_args, unsigned int prop_count,
int test_vsync, int flip_plane_id)
{ unsigned int num_planes; const char *obj_type = NULL; @@ -1753,7 +1916,8 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return -1; }
ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo, fb_id);
ret = allocate_fbs(dev, req, dev->resources, prop_args, prop_count, bo,
fb_id, flip_plane_id); if (ret < 0) { free(fb_id); free(bo);
@@ -1769,6 +1933,10 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return ret; }
if (test_vsync)
atomic_test_page_flip(dev, req, dev->resources,
prop_args, prop_count, flip_plane_id);
getchar(); deallocate_fbs(dev->fd, num_planes, fb_id, bo);
@@ -1778,7 +1946,7 @@ static int atomic_modeset(struct device *dev, drmModeAtomicReqPtr req, return 0; }
-static char optstr[] = "acdD:efM:P:ps:Cvw:"; +static char optstr[] = "acdD:efM:P:ps:CvV:w:";
int main(int argc, char **argv) { @@ -1792,7 +1960,7 @@ int main(int argc, char **argv) const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc", "msm", "sti", "tegra", "imx-drm", "rockchip", "atmel-hlcdc" }; char *device = NULL; char *module = NULL;
unsigned int i;
unsigned int i, flip_plane_id = 0; unsigned int count = 0, plane_count = 0; unsigned int prop_count = 0; struct pipe_arg *pipe_args = NULL;
@@ -1873,6 +2041,11 @@ int main(int argc, char **argv) case 'v': test_vsync = 1; break;
case 'V':
if (sscanf(optarg, "%u", &flip_plane_id) != 1)
usage(argv[0]);
test_vsync = 1;
break; case 'w': prop_args = realloc(prop_args, (prop_count + 1) * sizeof *prop_args);
@@ -1925,11 +2098,16 @@ int main(int argc, char **argv) return -1; }
if (test_vsync && !count) {
if (test_vsync && (!count && !is_atomic)) { fprintf(stderr, "page flipping requires at least one -s option.\n"); return -1; }
if (test_vsync && is_atomic && flip_plane_id == 0) {
fprintf(stderr, "fliping plane id must be set for atomic pageflip\n");
And how does average Joe find out the ID ? Something feels quite funny with this approach.
Hyungwon, despite my nitpicking your work looks quite good. The above question is rather important and I take care of everything else -either before pushing or as a follow up patch-es, depending on your preference. Let me know how you feel about it.
Thanks Emil
Hi Hyungwon
I completely missed out that you've sent an updated version of the series. I will take a look at them later on tonight. Meanwhile have you looked at the atomic tests/helpers work from Thierry [1] ? It creates nice simple helpers (as opposed to a single massive C file like modetest) and I'm leaning that there is quite a lot of code that can be reused from there.
Speaking of which Thierry, What is happening with these patches ? Last time you've respun them I've pinged you to send them over for inclusion. There was a trivial fix needed here or there but they were in pretty good shape.
Thanks Emil
Hello all,
+To Thierry Reding
On Thu, 26 Nov 2015 16:42:01 +0000 Emil Velikov emil.l.velikov@gmail.com wrote:
Hi Hyungwon
I completely missed out that you've sent an updated version of the series. I will take a look at them later on tonight. Meanwhile have you looked at the atomic tests/helpers work from Thierry [1] ? It creates nice simple helpers (as opposed to a single massive C file like modetest) and I'm leaning that there is quite a lot of code that can be reused from there.
Speaking of which Thierry, What is happening with these patches ? Last time you've respun them I've pinged you to send them over for inclusion. There was a trivial fix needed here or there but they were in pretty good shape.
Yes. I checked it now. It would be more clear concise, if they comes. Would it be better to wait Thierry for sending them again? Can you afford to do that, Thierry?
BRs, Hyungwon Hwang
Thanks Emil
On Fri, Nov 27, 2015 at 11:37:33AM +0900, Hyungwon Hwang wrote:
Hello all,
+To Thierry Reding
On Thu, 26 Nov 2015 16:42:01 +0000 Emil Velikov emil.l.velikov@gmail.com wrote:
Hi Hyungwon
I completely missed out that you've sent an updated version of the series. I will take a look at them later on tonight. Meanwhile have you looked at the atomic tests/helpers work from Thierry [1] ? It creates nice simple helpers (as opposed to a single massive C file like modetest) and I'm leaning that there is quite a lot of code that can be reused from there.
Speaking of which Thierry, What is happening with these patches ? Last time you've respun them I've pinged you to send them over for inclusion. There was a trivial fix needed here or there but they were in pretty good shape.
Yes. I checked it now. It would be more clear concise, if they comes. Would it be better to wait Thierry for sending them again? Can you afford to do that, Thierry?
Yeah, I think I can do that. It'll probably take until tomorrow for me to find a free slot to rebase and send out again.
Thierry
dri-devel@lists.freedesktop.org