From: Rob Clark rob@ti.com
Signed-off-by: Rob Clark rob@ti.com --- tests/modetest/modetest.c | 166 ++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 157 insertions(+), 9 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 1e4ec91..2936de0 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -51,6 +51,7 @@
#include "xf86drm.h" #include "xf86drmMode.h" +#include "drm_fourcc.h" #include "libkms.h"
#ifdef HAVE_CAIRO @@ -267,6 +268,49 @@ void dump_framebuffers(void) printf("\n"); }
+static void dump_planes(void) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + int i, j; + + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return; + } + + printf("Planes:\n"); + printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n"); + for (i = 0; i < plane_resources->count_planes; i++) { + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n", + ovr->plane_id, ovr->crtc_id, ovr->fb_id, + ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, + ovr->gamma_size); + + if (!ovr->count_formats) + continue; + + printf(" formats:"); + for (j = 0; j < ovr->count_formats; j++) + printf(" %4.4s", (char *)&ovr->formats[j]); + printf("\n"); + + drmModeFreePlane(ovr); + } + printf("\n"); + + return; +} + /* * Mode setting with the kernel interfaces is a bit of a chore. * First you have to find the connector in question and make sure the @@ -280,11 +324,18 @@ struct connector { drmModeModeInfo *mode; drmModeEncoder *encoder; int crtc; + int pipe; unsigned int fb_id[2], current_fb_id; struct timeval start;
int swap_count; -}; +}; + +struct plane { + uint32_t con_id; /* the id of connector to bind to */ + uint32_t w, h; + unsigned int fb_id; +};
static void connector_find_mode(struct connector *c) @@ -351,6 +402,15 @@ connector_find_mode(struct connector *c)
if (c->crtc == -1) c->crtc = c->encoder->crtc_id; + + /* and figure out which crtc index it is: */ + for (i = 0; i < resources->count_crtcs; i++) { + if (c->crtc == resources->crtcs[i]) { + c->pipe = i; + break; + } + } + }
static struct kms_bo * @@ -534,13 +594,83 @@ page_flip_handler(int fd, unsigned int frame, } }
+static int +set_plane(struct kms_driver *kms, struct connector *c, struct plane *p) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ + uint32_t plane_id = 0; + struct kms_bo *plane_bo; + uint32_t plane_flags = 0; + int i, crtc_x, crtc_y, crtc_w, crtc_h; + + /* find an unused plane which can be connected to our crtc */ + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return -1; + } + + for (i = 0; i < plane_resources->count_planes && !plane_id; i++) { + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + return -1; + } + + if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id) + plane_id = ovr->plane_id; + + drmModeFreePlane(ovr); + } + + if (!plane_id) { + fprintf(stderr, "failed to find plane!\n"); + return -1; + } + + /* TODO.. would be nice to test YUV overlays.. */ + if (create_test_buffer(kms, p->w, p->h, &pitches[0], &plane_bo)) + return -1; + + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + + /* just use single plane format for now.. */ + if (drmModeAddFB2(fd, p->w, p->h, DRM_FORMAT_XRGB8888, + handles, pitches, offsets, &p->fb_id, plane_flags)) { + fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); + return -1; + } + + /* ok, boring.. but for now put in middle of screen: */ + crtc_x = c->mode->hdisplay / 3; + crtc_y = c->mode->vdisplay / 3; + crtc_w = crtc_x; + crtc_h = crtc_y; + + /* note src coords (last 4 args) are in Q16 format */ + if (drmModeSetPlane(fd, plane_id, c->crtc, p->fb_id, + plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, p->w << 16, p->h << 16)) { + fprintf(stderr, "failed to enable plane: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + static void -set_mode(struct connector *c, int count, int page_flip) +set_mode(struct connector *c, int count, struct plane *p, int plane_count, + int page_flip) { struct kms_driver *kms; struct kms_bo *bo, *other_bo; unsigned int fb_id, other_fb_id; - int i, ret, width, height, x, stride; + int i, j, ret, width, height, x, stride; unsigned handle; drmEventContext evctx;
@@ -593,6 +723,12 @@ set_mode(struct connector *c, int count, int page_flip) fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); return; } + + /* if we have a plane/overlay to show, set that up now: */ + for (j = 0; j < plane_count; j++) + if (p[j].con_id == c[i].id) + if (set_plane(kms, &c[i], &p[j])) + return; }
if (!page_flip) @@ -676,19 +812,20 @@ set_mode(struct connector *c, int count, int page_flip)
extern char *optarg; extern int optind, opterr, optopt; -static char optstr[] = "ecpmfs:v"; +static char optstr[] = "ecpmfs:P:v";
void usage(char *name) { fprintf(stderr, "usage: %s [-ecpmf]\n", name); fprintf(stderr, "\t-e\tlist encoders\n"); fprintf(stderr, "\t-c\tlist connectors\n"); - fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); fprintf(stderr, "\t-m\tlist modes\n"); fprintf(stderr, "\t-f\tlist framebuffers\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); + fprintf(stderr, "\t-P <connector_id>:<w>x<h>\tset a plane\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); exit(0); } @@ -719,12 +856,13 @@ static int page_flipping_supported(int fd) int main(int argc, char **argv) { int c; - int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; int test_vsync = 0; char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm" }; char *modeset = NULL; - int i, count = 0; + int i, count = 0, plane_count = 0; struct connector con_args[2]; + struct plane plane_args[2]; opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { @@ -737,6 +875,7 @@ int main(int argc, char **argv) break; case 'p': crtcs = 1; + planes = 1; break; case 'm': modes = 1; @@ -760,6 +899,14 @@ int main(int argc, char **argv) usage(argv[0]); count++; break; + case 'P': + if (sscanf(optarg, "%d:%dx%d", + &plane_args[plane_count].con_id, + &plane_args[plane_count].w, + &plane_args[plane_count].h) != 3) + usage(argv[0]); + plane_count++; + break; default: usage(argv[0]); break; @@ -767,7 +914,7 @@ int main(int argc, char **argv) }
if (argc == 1) - encoders = connectors = crtcs = modes = framebuffers = 1; + encoders = connectors = crtcs = planes = modes = framebuffers = 1;
for (i = 0; i < ARRAY_SIZE(modules); i++) { printf("trying to load module %s...", modules[i]); @@ -801,10 +948,11 @@ int main(int argc, char **argv) dump_resource(encoders); dump_resource(connectors); dump_resource(crtcs); + dump_resource(planes); dump_resource(framebuffers);
if (count > 0) { - set_mode(con_args, count, test_vsync); + set_mode(con_args, count, plane_args, plane_count, test_vsync); getchar(); }
From: Rob Clark rob@ti.com
Signed-off-by: Rob Clark rob@ti.com --- This one is a bit f-ugly.. kms_bo_create() and dumb-scanout alloc only really knows about allocating 4byte/pixel buffers, so we just allocate oversized buffers and use the part we need. It is functional enough to test the driver (or at least omapdrm), but I'm not sure about how best to deal w/ kms_bo_create(). (Or perhaps I should only test YUV support in omapdrmtest tree, and not try to use generic kms_bo_create()?)
tests/modetest/modetest.c | 151 ++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 142 insertions(+), 9 deletions(-)
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 2936de0..36bdfff 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -335,6 +335,7 @@ struct plane { uint32_t con_id; /* the id of connector to bind to */ uint32_t w, h; unsigned int fb_id; + char format_str[5]; /* need to leave room for terminating \0 */ };
static void @@ -594,6 +595,63 @@ page_flip_handler(int fd, unsigned int frame, } }
+/* swap these for big endian.. */ +#define RED 2 +#define GREEN 1 +#define BLUE 0 + +static void +fill420(unsigned char *y, unsigned char *u, unsigned char *v, + int cs /*chroma pixel stride */, + int n, int width, int height, int stride) +{ + int i, j; + + /* paint the buffer with colored tiles, in blocks of 2x2 */ + for (j = 0; j < height; j+=2) { + unsigned char *y1p = y + j * stride; + unsigned char *y2p = y1p + stride; + unsigned char *up = u + (j/2) * stride * cs / 2; + unsigned char *vp = v + (j/2) * stride * cs / 2; + + for (i = 0; i < width; i+=2) { + div_t d = div(n+i+j, width); + uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); + unsigned char *rgbp = (unsigned char *)&rgb; + unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]); + + *(y2p++) = *(y1p++) = y; + *(y2p++) = *(y1p++) = y; + + *up = (rgbp[BLUE] - y) * 0.565 + 128; + *vp = (rgbp[RED] - y) * 0.713 + 128; + up += cs; + vp += cs; + } + } +} + +static void +fill422(unsigned char *virtual, int n, int width, int height, int stride) +{ + int i, j; + /* paint the buffer with colored tiles */ + for (j = 0; j < height; j++) { + uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride); + for (i = 0; i < width; i++) { + div_t d = div(n+i+j, width); + uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); + unsigned char *rgbp = (unsigned char *)&rgb; + unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]); + + *(ptr++) = y; + *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128; + *(ptr++) = y; + *(ptr++) = (rgbp[RED] - y) * 0.713 + 128; + } + } +} + static int set_plane(struct kms_driver *kms, struct connector *c, struct plane *p) { @@ -602,8 +660,8 @@ set_plane(struct kms_driver *kms, struct connector *c, struct plane *p) uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ uint32_t plane_id = 0; struct kms_bo *plane_bo; - uint32_t plane_flags = 0; - int i, crtc_x, crtc_y, crtc_w, crtc_h; + uint32_t plane_flags = 0, format; + int i, ret, crtc_x, crtc_y, crtc_w, crtc_h;
/* find an unused plane which can be connected to our crtc */ plane_resources = drmModeGetPlaneResources(fd); @@ -627,19 +685,87 @@ set_plane(struct kms_driver *kms, struct connector *c, struct plane *p) drmModeFreePlane(ovr); }
+ fprintf(stderr, "testing %dx%d@%s overlay plane\n", + p->w, p->h, p->format_str); + if (!plane_id) { fprintf(stderr, "failed to find plane!\n"); return -1; }
- /* TODO.. would be nice to test YUV overlays.. */ - if (create_test_buffer(kms, p->w, p->h, &pitches[0], &plane_bo)) - return -1; + if (!strcmp(p->format_str, "XR24")) { + if (create_test_buffer(kms, p->w, p->h, &pitches[0], &plane_bo)) + return -1; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + format = DRM_FORMAT_XRGB8888; + } else { + void *virtual; + + /* TODO: this always allocates a buffer for 32bpp RGB.. but for + * YUV formats, we don't use all of it.. since 4bytes/pixel is + * worst case, so live with it for now and just don't use all + * the buffer: + */ + plane_bo = allocate_buffer(kms, p->w, p->h, &pitches[0]); + if (!plane_bo) + return -1;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + ret = kms_bo_map(plane_bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-ret)); + kms_bo_destroy(&plane_bo); + return -1; + } + + /* just testing a limited # of formats to test single + * and multi-planar path.. would be nice to add more.. + */ + if (!strcmp(p->format_str, "YUYV")) { + pitches[0] = p->w * 2; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + + fill422(virtual, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_YUYV; + } else if (!strcmp(p->format_str, "NV12")) { + pitches[0] = p->w; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + pitches[1] = p->w; + offsets[1] = p->w * p->h; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]); + + fill420(virtual, virtual+offsets[1], virtual+offsets[1]+1, + 2, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_NV12; + } else if (!strcmp(p->format_str, "YV12")) { + pitches[0] = p->w; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + pitches[1] = p->w / 2; + offsets[1] = p->w * p->h; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]); + pitches[2] = p->w / 2; + offsets[2] = offsets[1] + (p->w * p->h) / 4; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]); + + fill420(virtual, virtual+offsets[1], virtual+offsets[2], + 1, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_YVU420; + } else { + fprintf(stderr, "Unknown format: %s\n", p->format_str); + return -1; + } + + kms_bo_unmap(plane_bo); + }
/* just use single plane format for now.. */ - if (drmModeAddFB2(fd, p->w, p->h, DRM_FORMAT_XRGB8888, + if (drmModeAddFB2(fd, p->w, p->h, format, handles, pitches, offsets, &p->fb_id, plane_flags)) { fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); return -1; @@ -826,6 +952,7 @@ void usage(char *name) fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); fprintf(stderr, "\t-P <connector_id>:<w>x<h>\tset a plane\n"); + fprintf(stderr, "\t-P <connector_id>:<w>x<h>@<format>\tset a plane\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); exit(0); } @@ -862,7 +989,7 @@ int main(int argc, char **argv) char *modeset = NULL; int i, count = 0, plane_count = 0; struct connector con_args[2]; - struct plane plane_args[2]; + struct plane plane_args[2] = {0}; opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { @@ -900,7 +1027,13 @@ int main(int argc, char **argv) count++; break; case 'P': - if (sscanf(optarg, "%d:%dx%d", + strcpy(plane_args[plane_count].format_str, "XR24"); + if (sscanf(optarg, "%d:%dx%d@%4s", + &plane_args[plane_count].con_id, + &plane_args[plane_count].w, + &plane_args[plane_count].h, + plane_args[plane_count].format_str) != 4 && + sscanf(optarg, "%d:%dx%d", &plane_args[plane_count].con_id, &plane_args[plane_count].w, &plane_args[plane_count].h) != 3)
dri-devel@lists.freedesktop.org