add video buffer support
authorRob Clark <rob@ti.com>
Sat, 21 Jan 2012 00:09:13 +0000 (18:09 -0600)
committerRob Clark <rob@ti.com>
Thu, 26 Jan 2012 15:41:32 +0000 (09:41 -0600)
dmabuftest.c
fliptest.c
util/Makefile.am
util/display-kms.c
util/util.c
util/util.h
util/v4l2.c

index 1bb3c394660ea5328b6902435b82ad48942bae08..a9f41e8a6afd73c65a52cf5ea5af3eb22694cd2a 100644 (file)
@@ -21,7 +21,7 @@
 #define NBUF 3
 #define CNT  500
 
-void
+static void
 usage(char *name)
 {
        MSG("Usage: %s [OPTION]...", name);
@@ -36,7 +36,9 @@ main(int argc, char **argv)
 {
        struct display *disp;
        struct v4l2 *v4l2;
+       struct buffer *framebuf;
        struct buffer **buffers;
+       uint32_t fourcc, width, height;
        int ret, i;
 
        MSG("Opening Display..");
@@ -47,7 +49,7 @@ main(int argc, char **argv)
        }
 
        MSG("Opening V4L2..");
-       v4l2 = v4l2_open(argc, argv);
+       v4l2 = v4l2_open(argc, argv, &fourcc, &width, &height);
        if (!v4l2) {
                usage(argv[0]);
                return 1;
@@ -59,7 +61,9 @@ main(int argc, char **argv)
                return 0;
        }
 
-       buffers = disp_get_buffers(disp, NBUF);
+       framebuf = disp_get_fb(disp);
+
+       buffers = disp_get_vid_buffers(disp, NBUF, fourcc, width, height);
        if (!buffers) {
                return 1;
        }
@@ -73,7 +77,8 @@ main(int argc, char **argv)
        v4l2_streamon(v4l2);
        for (i = 1; i < CNT; i++) {
                v4l2_qbuf(v4l2, buffers[i % NBUF]);
-               ret = disp_post_buffer(disp, v4l2_dqbuf(v4l2));
+               ret = disp_post_vid_buffer(disp, v4l2_dqbuf(v4l2),
+                               0, 0, width, height);
                if (ret) {
                        return ret;
                }
index ea424a8868aca6976ea2b057614651358c21ccb4..cedab45fd091f047952dc11c7ebb6d665f764d26 100644 (file)
@@ -21,7 +21,7 @@
 #define NBUF 3
 #define CNT  500
 
-void
+static void
 usage(char *name)
 {
        MSG("Usage: %s [OPTION]...", name);
index 864ee25257c6e13763af183060b7239604e38128..5c063dc58f152819f49d2ed8b47c393424dfcc0e 100644 (file)
@@ -19,12 +19,11 @@ noinst_LTLIBRARIES = libutil.la
 
 libutil_la_SOURCES = \
        display-kms.c \
-       display-x11.c \
        v4l2.c \
        util.c
 
 if ENABLE_X11
-libutil_la_SOURCES += x11.c
+libutil_la_SOURCES += display-x11.c
 endif
 
 libutil_la_LIBADD = @DRM_LIBS@ @X11_LIBS@
index 57998b4d2a2870ab34b0d02cd131b6d7858a7f9a..808945ca0c0b2501e22a3b10d0d3f2005be17a62 100644 (file)
@@ -35,18 +35,21 @@ struct connector {
        drmModeModeInfo *mode;
        drmModeEncoder *encoder;
        int crtc;
+       int pipe;
 };
 
 #define to_display_kms(x) container_of(x, struct display_kms, base)
 struct display_kms {
        struct display base;
 
-       int connectors_count;
+       uint32_t connectors_count;
        struct connector connector[10];
+       drmModePlane *ovr[10];
 
        int scheduled_flips, completed_flips;
        uint32_t bo_flags;
        drmModeResPtr resources;
+       drmModePlaneRes *plane_resources;
        struct buffer *current;
 };
 
@@ -56,13 +59,47 @@ struct buffer_kms {
        uint32_t fb_id;
 };
 
+static struct omap_bo *
+alloc_bo(struct display *disp, uint32_t bpp, uint32_t width, uint32_t height,
+               uint32_t *bo_handle, uint32_t *pitch)
+{
+       struct display_kms *disp_kms = to_display_kms(disp);
+       struct omap_bo *bo;
+       uint32_t bo_flags = disp_kms->bo_flags;
+
+       if ((bo_flags & OMAP_BO_TILED) == OMAP_BO_TILED) {
+               bo_flags &= ~OMAP_BO_TILED;
+               if (bpp == 8) {
+                       bo_flags |= OMAP_BO_TILED_8;
+               } else if (bpp == 16) {
+                       bo_flags |= OMAP_BO_TILED_16;
+               } else if (bpp == 32) {
+                       bo_flags |= OMAP_BO_TILED_32;
+               }
+       }
+
+       bo_flags |= OMAP_BO_WC;
+
+       if (bo_flags & OMAP_BO_TILED) {
+               bo = omap_bo_new_tiled(disp->dev, width, height, bo_flags);
+       } else {
+               bo = omap_bo_new(disp->dev, width * height * bpp / 8, bo_flags);
+       }
+
+       if (bo) {
+               *bo_handle = omap_bo_handle(bo);
+               *pitch = width * bpp / 8;
+       }
+
+       return bo;
+}
+
 static struct buffer *
 alloc_buffer(struct display *disp, uint32_t fourcc, uint32_t w, uint32_t h)
 {
-       struct display_kms *disp_kms = to_display_kms(disp);
        struct buffer_kms *buf_kms;
        struct buffer *buf;
-       uint32_t depth, bpp;
+       uint32_t bo_handles[4] = {0}, offsets[4] = {0};
        int ret;
 
        buf_kms = calloc(1, sizeof(*buf_kms));
@@ -76,43 +113,48 @@ alloc_buffer(struct display *disp, uint32_t fourcc, uint32_t w, uint32_t h)
        buf->width = w;
        buf->height = h;
 
+       buf->nbo = 1;
+
+       if (!fourcc)
+               fourcc = FOURCC('A','R','2','4');
+
        switch(fourcc) {
-       case 0:
-               /* native fb format: */
-               buf->stride = 4 * buf->width;
-               depth = 24;
-               bpp = 32;
+       case FOURCC('A','R','2','4'):
+               buf->nbo = 1;
+               buf->bo[0] = alloc_bo(disp, 32, buf->width, buf->height,
+                               &bo_handles[0], &buf->pitches[0]);
+               break;
+       case FOURCC('U','Y','V','Y'):
+       case FOURCC('Y','U','Y','V'):
+               buf->nbo = 1;
+               buf->bo[0] = alloc_bo(disp, 16, buf->width, buf->height,
+                               &bo_handles[0], &buf->pitches[0]);
+               break;
+       case FOURCC('N','V','1','2'):
+               buf->nbo = 2;
+               buf->bo[0] = alloc_bo(disp, 8, buf->width, buf->height,
+                               &bo_handles[0], &buf->pitches[0]);
+               buf->bo[1] = alloc_bo(disp, 16, buf->width/2, buf->height/2,
+                               &bo_handles[1], &buf->pitches[1]);
+               break;
+       case FOURCC('I','4','2','0'):
+               buf->nbo = 3;
+               buf->bo[0] = alloc_bo(disp, 8, buf->width, buf->height,
+                               &bo_handles[0], &buf->pitches[0]);
+               buf->bo[1] = alloc_bo(disp, 8, buf->width/2, buf->height/2,
+                               &bo_handles[1], &buf->pitches[1]);
+               buf->bo[2] = alloc_bo(disp, 8, buf->width/2, buf->height/2,
+                               &bo_handles[2], &buf->pitches[2]);
                break;
-       /*TODO add YUV formats.. */
        default:
                ERROR("invalid format: 0x%08x", fourcc);
                goto fail;
        }
 
-       if (disp_kms->bo_flags & OMAP_BO_TILED) {
-               buf->bo = omap_bo_new_tiled(disp->dev, buf->width, buf->height,
-                               disp_kms->bo_flags);
-       } else {
-               uint32_t sz = buf->stride * buf->height;
-               buf->bo = omap_bo_new(disp->dev, sz, disp_kms->bo_flags);
-       }
-
-       if (!buf->bo) {
-               ERROR("allocation failed");
-               goto fail;
-       }
-
-       if (!fourcc) {
-               ret = drmModeAddFB(disp->fd, buf->width, buf->height, depth, bpp,
-                               buf->stride, omap_bo_handle(buf->bo), &buf_kms->fb_id);
-       } else {
-               // XXX use drmModeAddFB2()..
-               ERROR("TODO");
-               goto fail;
-       }
-
+       ret = drmModeAddFB2(disp->fd, buf->width, buf->height, fourcc,
+                       bo_handles, buf->pitches, offsets, &buf_kms->fb_id, 0);
        if (ret) {
-               ERROR("drmModeAddFB(2) failed: %s (%d)", strerror(errno), ret);
+               ERROR("drmModeAddFB2 failed: %s (%d)", strerror(errno), ret);
                goto fail;
        }
 
@@ -182,7 +224,8 @@ post_buffer(struct display *disp, struct buffer *buf)
 {
        struct display_kms *disp_kms = to_display_kms(disp);
        struct buffer_kms *buf_kms = to_buffer_kms(buf);
-       int i, ret, last_err = 0, x = 0;
+       int ret, last_err = 0, x = 0;
+       uint32_t i;
 
        for (i = 0; i < disp_kms->connectors_count; i++) {
                struct connector *connector = &disp_kms->connector[i];
@@ -251,6 +294,60 @@ post_buffer(struct display *disp, struct buffer *buf)
        return last_err;
 }
 
+static int
+post_vid_buffer(struct display *disp, struct buffer *buf,
+               uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+       struct display_kms *disp_kms = to_display_kms(disp);
+       struct buffer_kms *buf_kms = to_buffer_kms(buf);
+       int ret = 0;
+       uint32_t i, j;
+
+       /* ensure we have the overlay setup: */
+       for (i = 0; i < disp_kms->connectors_count; i++) {
+               struct connector *connector = &disp_kms->connector[i];
+               uint32_t used_planes = 0;
+               drmModeModeInfo *mode = connector->mode;
+
+               if (! mode) {
+                       continue;
+               }
+
+               if (! disp_kms->ovr[i]) {
+
+                       for (j = 0; j < disp_kms->plane_resources->count_planes; j++) {
+                               drmModePlane *ovr = drmModeGetPlane(disp->fd,
+                                               disp_kms->plane_resources->planes[j]);
+                               if ((ovr->possible_crtcs & (1 << connector->pipe)) &&
+                                               !(used_planes & (1 << j))) {
+                                       disp_kms->ovr[i] = ovr;
+                                       used_planes |= (1 << j);
+                                       break;
+                               }
+                       }
+               }
+
+               if (! disp_kms->ovr[i]) {
+                       MSG("Could not find plane for crtc %d", connector->crtc);
+                       ret = -1;
+                       /* carry on and see if we can find at least one usable plane */
+                       continue;
+               }
+
+               ret = drmModeSetPlane(disp->fd, disp_kms->ovr[i]->plane_id,
+                               connector->crtc, buf_kms->fb_id, 0,
+                               /* make video fullscreen: */
+                               0, 0, mode->hdisplay, mode->vdisplay,
+                               /* source/cropping coordinates are given in Q16 */
+                               x << 16, y << 16, w << 16, h << 16);
+               if (ret) {
+                       ERROR("failed to enable plane %d: %s",
+                                       disp_kms->ovr[i]->plane_id, strerror(errno));
+               }
+       }
+
+       return ret;
+}
 
 static void
 connector_find_mode(struct display *disp, struct connector *c)
@@ -320,13 +417,21 @@ connector_find_mode(struct display *disp, 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 < disp_kms->resources->count_crtcs; i++) {
+               if (c->crtc == (int)disp_kms->resources->crtcs[i]) {
+                       c->pipe = i;
+                       break;
+               }
+       }
 }
 
 void
 disp_kms_usage(void)
 {
        MSG("KMS Display Options:");
-       MSG("\t-t <tiled-mode>\t8, 16, or 32");
+       MSG("\t-t <tiled-mode>\t8, 16, 32, or auto");
        MSG("\t-s <connector_id>:<mode>\tset a mode");
        MSG("\t-s <connector_id>@<crtc_id>:<mode>\tset a mode");
 }
@@ -360,6 +465,7 @@ disp_kms_open(int argc, char **argv)
        disp->get_buffers = get_buffers;
        disp->get_vid_buffers = get_vid_buffers;
        disp->post_buffer = post_buffer;
+       disp->post_vid_buffer = post_vid_buffer;
 
        disp_kms->resources = drmModeGetResources(disp->fd);
        if (!disp_kms->resources) {
@@ -367,6 +473,12 @@ disp_kms_open(int argc, char **argv)
                goto fail;
        }
 
+       disp_kms->plane_resources = drmModeGetPlaneResources(disp->fd);
+       if (!disp_kms->plane_resources) {
+               ERROR("drmModeGetPlaneResources failed: %s", strerror(errno));
+               goto fail;
+       }
+
        /* note: set args to NULL after we've parsed them so other modules know
         * that it is already parsed (since the arg parsing is decentralized)
         */
@@ -377,7 +489,9 @@ disp_kms_open(int argc, char **argv)
                if (!strcmp("-t", argv[i])) {
                        int n;
                        argv[i++] = NULL;
-                       if (sscanf(argv[i], "%d", &n) != 1) {
+                       if (!strcmp(argv[i], "auto")) {
+                               n = 0;
+                       } else if (sscanf(argv[i], "%d", &n) != 1) {
                                ERROR("invalid arg: %s", argv[i]);
                                goto fail;
                        }
@@ -390,6 +504,8 @@ disp_kms_open(int argc, char **argv)
                                disp_kms->bo_flags |= OMAP_BO_TILED_16;
                        } else if (n == 32) {
                                disp_kms->bo_flags |= OMAP_BO_TILED_32;
+                       } else if (n == 0) {
+                               disp_kms->bo_flags |= OMAP_BO_TILED;
                        } else {
                                ERROR("invalid arg: %s", argv[i]);
                                goto fail;
@@ -419,7 +535,7 @@ disp_kms_open(int argc, char **argv)
 
        disp->width = 0;
        disp->height = 0;
-       for (i = 0; i < disp_kms->connectors_count; i++) {
+       for (i = 0; i < (int)disp_kms->connectors_count; i++) {
                struct connector *c = &disp_kms->connector[i];
                connector_find_mode(disp, c);
                if (c->mode == NULL)
index ab12a68ad649b2585788cc3590c9596464ee3fa9..92f9a0c302285b7e8abfe9f9a3cccccaaec5622e 100644 (file)
@@ -56,6 +56,18 @@ disp_open(int argc, char **argv)
        return disp;
 }
 
+struct buffer *
+disp_get_fb(struct display *disp)
+{
+       struct buffer **bufs = disp_get_buffers(disp, 1);
+       if (!bufs)
+               return NULL;
+       fill(bufs[0], 42);
+       disp_post_buffer(disp, bufs[0]);
+       return bufs[0];
+}
+
+
 int
 check_args(int argc, char **argv)
 {
@@ -146,34 +158,42 @@ fill422(unsigned char *virtual, int n, int width, int height, int stride)
 
 
 void
-fill(struct buffer *buf, int i)
+fill(struct buffer *buf, int n)
 {
-       void *ptr;
+       int i;
 
-       omap_bo_cpu_prep(buf->bo, OMAP_GEM_WRITE);
-       ptr = omap_bo_map(buf->bo);
+       for (i = 0; i < buf->nbo; i++)
+               omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
 
        switch(buf->fourcc) {
        case 0: {
-               fillRGB4(ptr, i, buf->width, buf->height, buf->stride);
+               assert(buf->nbo == 1);
+               fillRGB4(omap_bo_map(buf->bo[0]), n,
+                               buf->width, buf->height, buf->pitches[0]);
                break;
        }
        case FOURCC('Y','U','Y','V'): {
-               fill422(ptr, i, buf->width, buf->height, buf->stride);
+               assert(buf->nbo == 1);
+               fill422(omap_bo_map(buf->bo[0]), n,
+                               buf->width, buf->height, buf->pitches[0]);
                break;
        }
        case FOURCC('N','V','1','2'): {
-               unsigned char *y = ptr;
-               unsigned char *u = y + (buf->width * buf->stride);
-               unsigned char *v = u + 1;
-               fill420(y, u, v, 2, i, buf->width, buf->height, buf->stride);
+               unsigned char *y, *u, *v;
+               assert(buf->nbo == 2);
+               y = omap_bo_map(buf->bo[0]);
+               u = omap_bo_map(buf->bo[1]);
+               v = u + 1;
+               fill420(y, u, v, 2, n, buf->width, buf->height, buf->pitches[0]);
                break;
        }
        case FOURCC('I','4','2','0'): {
-               unsigned char *y = ptr;
-               unsigned char *u = y + (buf->width * buf->stride);
-               unsigned char *v = u + (buf->width * buf->stride) / 4;
-               fill420(y, u, v, 1, i, buf->width, buf->height, buf->stride);
+               unsigned char *y, *u, *v;
+               assert(buf->nbo == 3);
+               y = omap_bo_map(buf->bo[0]);
+               u = omap_bo_map(buf->bo[1]);
+               v = omap_bo_map(buf->bo[2]);
+               fill420(y, u, v, 1, n, buf->width, buf->height, buf->pitches[0]);
                break;
        }
        default:
@@ -181,5 +201,6 @@ fill(struct buffer *buf, int i)
                break;
        }
 
-       omap_bo_cpu_fini(buf->bo, OMAP_GEM_WRITE);
+       for (i = 0; i < buf->nbo; i++)
+               omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);
 }
index 33af61deb06f963f724fefffdcbcd8cdd0a235bc..b05b526c017772e7bf0a70a2b6535d61a6d5b082 100644 (file)
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include <omap_drm.h>
 #include <omap_drmif.h>
  */
 
 struct buffer {
-       uint32_t fourcc, width, height, stride;
-       struct omap_bo *bo;
+       uint32_t fourcc, width, height;
+       int nbo;
+       struct omap_bo *bo[4];
+       uint32_t pitches[4];
 };
 
 struct display {
@@ -52,6 +55,8 @@ struct display {
        struct buffer ** (*get_vid_buffers)(struct display *disp,
                        uint32_t n, uint32_t fourcc, uint32_t w, uint32_t h);
        int (*post_buffer)(struct display *disp, struct buffer *buf);
+       int (*post_vid_buffer)(struct display *disp, struct buffer *buf,
+                       uint32_t x, uint32_t y, uint32_t w, uint32_t h);
 };
 
 /* Print display related help */
@@ -84,6 +89,20 @@ disp_post_buffer(struct display *disp, struct buffer *buf)
        return disp->post_buffer(disp, buf);
 }
 
+/* flip to / post the specified video buffer */
+static inline int
+disp_post_vid_buffer(struct display *disp, struct buffer *buf,
+               uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+       return disp->post_vid_buffer(disp, buf, x, y, w, h);
+}
+
+/* helper to setup the display for apps that just need video with
+ * no flipchain on the GUI layer
+ */
+struct buffer * disp_get_fb(struct display *disp);
+
+
 /* V4L2 utilities:
  */
 
@@ -93,7 +112,8 @@ struct v4l2;
 void v4l2_usage(void);
 
 /* Open v4l2 (and media0??) XXX */
-struct v4l2 * v4l2_open(int argc, char **argv);
+struct v4l2 * v4l2_open(int argc, char **argv, uint32_t *fourcc,
+               uint32_t *width, uint32_t *height);
 
 /* Share the buffers w/ v4l2 via dmabuf */
 int v4l2_reqbufs(struct v4l2 *v4l2, struct buffer **bufs, uint32_t n);
index a84ce4452024389209e92843aafbe25781727f08..4dbc4e911f89b3da18401637b472364420d7d49d 100644 (file)
@@ -217,7 +217,8 @@ media_setup(struct v4l2_format *format)
 
 /* Open v4l2 (and media0??) XXX */
 struct v4l2 *
-v4l2_open(int argc, char **argv)
+v4l2_open(int argc, char **argv, uint32_t *fourcc,
+               uint32_t *width, uint32_t *height)
 {
        struct v4l2_format format = {
                        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -270,6 +271,10 @@ v4l2_open(int argc, char **argv)
                goto fail;
        }
 
+       *fourcc = format.fmt.pix.pixelformat;
+       *width  = format.fmt.pix.width;
+       *height = format.fmt.pix.height;
+
        if (mcf) {
                ret = media_setup(&format);
                if (ret < 0) {
@@ -328,14 +333,15 @@ v4l2_reqbufs(struct v4l2 *v4l2, struct buffer **bufs, uint32_t n)
        }
 
        for (i = 0; i < reqbuf.count; i++) {
+               assert(bufs[i]->nbo == 1); /* TODO add multi-planar support */
                v4l2->v4l2bufs[i] = (struct v4l2_buffer){
                        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                        .memory = V4L2_MEMORY_DMABUF,
                                        .index = i,
-                                       .m.fd = omap_bo_dmabuf(bufs[i]->bo),
+                                       .m.fd = omap_bo_dmabuf(bufs[i]->bo[0]),
                };
                ret = ioctl(v4l2->fd, VIDIOC_QUERYBUF, &v4l2->v4l2bufs[i]);
-               v4l2->v4l2bufs[i].m.fd = omap_bo_dmabuf(bufs[i]->bo);
+               v4l2->v4l2bufs[i].m.fd = omap_bo_dmabuf(bufs[i]->bo[0]);
                if (ret) {
                        ERROR("VIDIOC_QUERYBUF failed: %s (%d)", strerror(errno), ret);
                        return ret;
@@ -381,7 +387,9 @@ v4l2_qbuf(struct v4l2 *v4l2, struct buffer *buf)
        struct v4l2_buffer *v4l2buf = NULL;
        int i, ret, fd;
 
-       fd = omap_bo_dmabuf(buf->bo);
+       assert(buf->nbo == 1); /* TODO add multi-planar support */
+
+       fd = omap_bo_dmabuf(buf->bo[0]);
 
        for (i = 0; i < v4l2->nbufs; i++) {
                if (v4l2->v4l2bufs[i].m.fd == fd) {
@@ -423,9 +431,11 @@ v4l2_dqbuf(struct v4l2 *v4l2)
 
        buf = v4l2->bufs[v4l2buf.index];
 
-       if (omap_bo_dmabuf(buf->bo) != v4l2buf.m.fd) {
+       assert(buf->nbo == 1); /* TODO add multi-planar support */
+
+       if (omap_bo_dmabuf(buf->bo[0]) != v4l2buf.m.fd) {
                MSG("WARNING: camera gave us incorrect buffer: %d vs %d",
-                               omap_bo_dmabuf(buf->bo), v4l2buf.m.fd);
+                               omap_bo_dmabuf(buf->bo[0]), v4l2buf.m.fd);
        }
 
        return buf;