summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk_cubox@arm.linux.org.uk>2013-06-16 09:19:56 +0100
committerRussell King <rmk@arm.linux.org.uk>2013-06-16 09:21:12 +0100
commit695bae9eb303b5315cc17cf85c67dbff2c7007ae (patch)
tree37c645d17d9914bc6cf9218f1b0df6277701007e
parent3c6a0157c585cbce6c560bdc1a28765c0529d57f (diff)
downloadxf86-video-armada-695bae9eb303b5315cc17cf85c67dbff2c7007ae.tar.gz
xf86-video-armada-695bae9eb303b5315cc17cf85c67dbff2c7007ae.tar.xz
Add DRM plane support to Xv backend
Signed-off-by: Russell King <rmk@arm.linux.org.uk>
-rw-r--r--src/armada_drm_xv.c1445
1 files changed, 975 insertions, 470 deletions
diff --git a/src/armada_drm_xv.c b/src/armada_drm_xv.c
index b8188e0..ebe13b0 100644
--- a/src/armada_drm_xv.c
+++ b/src/armada_drm_xv.c
@@ -15,6 +15,7 @@
#include <armada_bufmgr.h>
#include "armada_drm.h"
+#include "drm_fourcc.h"
#include "xf86Crtc.h"
#include "xf86xv.h"
#include "fourcc.h"
@@ -24,60 +25,79 @@
#include "armada_ioctl.h"
#define FOURCC_VYUY 0x59555956
-#define XVIMAGE_VYUY \
- { \
- FOURCC_VYUY, XvYUV, LSBFirst, \
- { 'V', 'Y', 'U', 'Y', 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 }, \
- 16, XvPacked, 1, \
- 0, 0, 0, 0, \
- 8, 8, 8, \
- 1, 2, 2, \
- 1, 1, 1, \
- { 'V', 'Y', 'U', 'Y' }, \
- XvTopToBottom, \
- }
+#define GUID4CC(a,b,c,d) { a,b,c,d, 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 }
+#define XVIMAGE_VYUY { \
+ FOURCC_VYUY, XvYUV, LSBFirst, GUID4CC('V', 'Y', 'U', 'Y'), \
+ 16, XvPacked, 1, 0, 0, 0, 0, \
+ 8, 8, 8, 1, 2, 2, 1, 1, 1, "VYUY", XvTopToBottom, }
#define FOURCC_I422 0x32323449
-#define XVIMAGE_I422 \
- { \
- FOURCC_I422, XvYUV, LSBFirst, \
- { 'I', '4', '2', '2', 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 }, \
- 16, XvPlanar, 3, \
- 0, 0, 0, 0, \
- 8, 8, 8, \
- 1, 2, 2, \
- 1, 1, 1, \
- { 'Y', 'U', 'V' }, \
- XvTopToBottom, \
- }
+#define XVIMAGE_I422 { \
+ FOURCC_I422, XvYUV, LSBFirst, GUID4CC('I', '4', '2', '2'), \
+ 16, XvPlanar, 3, 0, 0, 0, 0, \
+ 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUV", XvTopToBottom, }
#define FOURCC_YV16 0x36315659
-#define XVIMAGE_YV16 \
- { \
- FOURCC_YV16, XvYUV, LSBFirst, \
- { 'Y', 'V', '1', '6', 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 }, \
- 16, XvPlanar, 3, \
- 0, 0, 0, 0, \
- 8, 8, 8, \
- 1, 2, 2, \
- 1, 1, 1, \
- { 'Y', 'V', 'U' }, \
- XvTopToBottom, \
- }
+#define XVIMAGE_YV16 { \
+ FOURCC_YV16, XvYUV, LSBFirst, GUID4CC('Y', 'V', '1', '6'), \
+ 16, XvPlanar, 3, 0, 0, 0, 0, \
+ 8, 8, 8, 1, 2, 2, 1, 1, 1, "YVU", XvTopToBottom, }
#define FOURCC_XVBO 0x4f425658
-#define XVIMAGE_XVBO \
- { \
- FOURCC_XVBO, XvYUV, LSBFirst, \
- { 'X', 'V', 'B', 'O', 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 }, \
- 16, XvPacked, 1, \
- 0, 0, 0, 0, \
- 8, 8, 8, \
- 1, 2, 2, \
- 1, 1, 1, \
- { 'U', 'Y', 'V', 'Y' }, \
- XvTopToBottom, \
- }
+#define XVIMAGE_XVBO { \
+ FOURCC_XVBO, XvYUV, LSBFirst, { 0 }, \
+ 16, XvPacked, 1, 0, 0, 0, 0, \
+ 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY", XvTopToBottom, }
+
+#define XVIMAGE_ARGB8888 { \
+ DRM_FORMAT_ARGB8888, XvRGB, LSBFirst, { 0 }, \
+ 32, XvPacked, 1, 24, 0xff0000, 0x00ff00, 0x0000ff, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "BGRA", XvTopToBottom, }
+
+#define XVIMAGE_ABGR8888 { \
+ DRM_FORMAT_ABGR8888, XvRGB, LSBFirst, { 0 }, \
+ 32, XvPacked, 1, 24, 0x0000ff, 0x00ff00, 0xff0000, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "RGBA", XvTopToBottom, }
+
+#define XVIMAGE_XRGB8888 { \
+ DRM_FORMAT_XRGB8888, XvRGB, LSBFirst, { 0 }, \
+ 32, XvPacked, 1, 24, 0xff0000, 0x00ff00, 0x0000ff, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "BGR", XvTopToBottom, }
+
+#define XVIMAGE_XBGR8888 { \
+ DRM_FORMAT_XBGR8888, XvRGB, LSBFirst, { 0 }, \
+ 32, XvPacked, 1, 24, 0x0000ff, 0x00ff00, 0xff0000, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "RGB", XvTopToBottom, }
+
+#define XVIMAGE_RGB888 { \
+ DRM_FORMAT_RGB888, XvRGB, LSBFirst, { 0 }, \
+ 24, XvPacked, 1, 24, 0xff0000, 0x00ff00, 0x0000ff, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "BGR", XvTopToBottom, }
+
+#define XVIMAGE_BGR888 { \
+ DRM_FORMAT_BGR888, XvRGB, LSBFirst, { 0 }, \
+ 24, XvPacked, 1, 24, 0x0000ff, 0x00ff00, 0xff0000, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "RGB", XvTopToBottom, }
+
+#define XVIMAGE_ARGB1555 { \
+ DRM_FORMAT_ARGB1555, XvRGB, LSBFirst, { 0 }, \
+ 16, XvPacked, 1, 15, 0x7c00, 0x03e0, 0x001f, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "BGRA", XvTopToBottom, }
+
+#define XVIMAGE_ABGR1555 { \
+ DRM_FORMAT_ABGR1555, XvRGB, LSBFirst, { 0 }, \
+ 16, XvPacked, 1, 15, 0x001f, 0x03e0, 0x7c00, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "RGBA", XvTopToBottom, }
+
+#define XVIMAGE_RGB565 { \
+ DRM_FORMAT_RGB565, XvRGB, LSBFirst, { 0 }, \
+ 16, XvPacked, 1, 16, 0xf800, 0x07e0, 0x001f, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "BGR", XvTopToBottom, }
+
+#define XVIMAGE_BGR565 { \
+ DRM_FORMAT_BGR565, XvRGB, LSBFirst, { 0 }, \
+ 16, XvPacked, 1, 16, 0x001f, 0x07e0, 0xf800, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, "RGB", XvTopToBottom, }
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
@@ -91,38 +111,61 @@ static Atom xvPipe;
/* Size of physical addresses via BMM */
typedef uint32_t phys_t;
+#define INVALID_PHYS (~(phys_t)0)
+
+#define NR_BUFS 3
+
+struct armada_format {
+ uint32_t drm_format;
+ XF86ImageRec xv_image;
+ uint32_t flags;
+};
struct drm_xv {
struct armada_drm_info *drm;
+
+ /* Common information */
xf86CrtcPtr desired_crtc;
Bool is_bmm;
Bool autopaint_colorkey;
- /* Cache the information */
- int image_fourcc;
- short image_width;
- short image_height;
- const XF86ImageRec *image;
- uint32_t image_flags;
+ /* Cached image information */
+ RegionRec clipBoxes;
+ int fourcc;
+ short width;
+ short height;
uint32_t image_size;
- int pitches[3];
- int offsets[3];
- int (*cvt)(struct drm_xv *, unsigned char *, struct drm_armada_bo **);
+ uint32_t pitches[3];
+ uint32_t offsets[3];
unsigned bo_idx;
- struct drm_armada_bo *bo[3];
- phys_t bo_phys[3];
-
- RegionRec clipBoxes;
+ struct {
+ struct drm_armada_bo *bo;
+ phys_t phys;
+ uint32_t fb_id;
+ } bufs[NR_BUFS];
+
+ struct drm_armada_bo *(*get_bo)(struct drm_xv *, unsigned char *, uint32_t *);
+
+ /* Plane information */
+ uint32_t plane_fb_id;
+ drmModePlanePtr plane;
+ drmModePlanePtr planes[2];
+ const struct armada_format *plane_format;
+#ifdef LEGACY_OVERLAY
+ /* Overlay information */
+ const XF86ImageRec *image;
+ struct drm_armada_overlay_put_image arg;
+#endif
struct drm_armada_overlay_attrs attrs;
- struct drm_armada_overlay_put_image arg;
};
static XF86VideoEncodingRec OverlayEncodings[] = {
{ 0, "XV_IMAGE", 2048, 2048, { 1, 1 }, },
};
+/* The list of visuals that which we can render against - anything really */
static XF86VideoFormatRec OverlayFormats[] = {
{ 8, PseudoColor },
{ 16, TrueColor },
@@ -147,35 +190,64 @@ static XF86AttributeRec OverlayAttributes[] = {
* not have any support for it but does have I422) so these comes at
* the very end, to try to avoid vlc complaining about them.
*/
-static XF86ImageRec OverlayImages[] = {
- XVIMAGE_I420,
- XVIMAGE_YV12,
- XVIMAGE_I422,
- XVIMAGE_YUY2,
- XVIMAGE_UYVY,
- XVIMAGE_VYUY,
- XVIMAGE_YV16,
- XVIMAGE_XVBO,
+static const struct armada_format armada_drm_formats[] = {
+ /* Standard Xv formats */
+ { DRM_FORMAT_UYVY, XVIMAGE_UYVY,
+ ARMADA_OVERLAY_YUV422 | ARMADA_OVERLAY_YUV_PACKED |
+ ARMADA_OVERLAY_Y_SWAP },
+ { DRM_FORMAT_YUYV, XVIMAGE_YUY2,
+ ARMADA_OVERLAY_YUV422 | ARMADA_OVERLAY_YUV_PACKED },
+ { DRM_FORMAT_YUV420, XVIMAGE_I420,
+ ARMADA_OVERLAY_YUV420 | ARMADA_OVERLAY_YUV_PLANAR },
+ { DRM_FORMAT_YVU420, XVIMAGE_YV12,
+ ARMADA_OVERLAY_YUV420 | ARMADA_OVERLAY_YUV_PLANAR },
+ /* Our own formats */
+ { DRM_FORMAT_YUV422, XVIMAGE_I422,
+ ARMADA_OVERLAY_YUV422 | ARMADA_OVERLAY_YUV_PLANAR },
+ { DRM_FORMAT_YVU422, XVIMAGE_YV16,
+ ARMADA_OVERLAY_YUV422 | ARMADA_OVERLAY_YUV_PLANAR },
+ { DRM_FORMAT_VYUY, XVIMAGE_VYUY,
+ ARMADA_OVERLAY_YUV422 | ARMADA_OVERLAY_YUV_PACKED |
+ ARMADA_OVERLAY_Y_SWAP | ARMADA_OVERLAY_UV_SWAP },
+ { DRM_FORMAT_ARGB8888, XVIMAGE_ARGB8888, },
+ { DRM_FORMAT_ABGR8888, XVIMAGE_ABGR8888, },
+ { DRM_FORMAT_XRGB8888, XVIMAGE_XRGB8888, },
+ { DRM_FORMAT_XBGR8888, XVIMAGE_XBGR8888, },
+ { DRM_FORMAT_RGB888, XVIMAGE_RGB888, },
+ { DRM_FORMAT_BGR888, XVIMAGE_BGR888, },
+ { DRM_FORMAT_ARGB1555, XVIMAGE_ARGB1555, },
+ { DRM_FORMAT_ABGR1555, XVIMAGE_ABGR1555, },
+ { DRM_FORMAT_RGB565, XVIMAGE_RGB565 },
+ { DRM_FORMAT_BGR565, XVIMAGE_BGR565 },
+ { 0, XVIMAGE_XVBO },
};
/* It would be nice to be given the image pointer... */
-static const XF86ImageRec *armada_drm_ovl_get_img(int image)
+static const struct armada_format *armada_drm_lookup_xvfourcc(int fmt)
{
- const XF86ImageRec *img = NULL;
- int i;
+ unsigned i;
- for (i = 0; i < sizeof(OverlayImages) / sizeof(XF86ImageRec); i++)
- if (OverlayImages[i].id == image) {
- img = &OverlayImages[i];
- break;
- }
+ for (i = 0; i < ARRAY_SIZE(armada_drm_formats); i++)
+ if (armada_drm_formats[i].xv_image.id == fmt)
+ return &armada_drm_formats[i];
+ return NULL;
+}
+
+static const struct armada_format *armada_drm_lookup_drmfourcc(uint32_t fmt)
+{
+ unsigned i;
- return img;
+ for (i = 0; i < ARRAY_SIZE(armada_drm_formats); i++)
+ if (armada_drm_formats[i].drm_format == fmt)
+ return &armada_drm_formats[i];
+ return NULL;
}
-static int armada_drm_ovl_set_img_info(const XF86ImageRec *img,
- int *pitch, int *offset, short width, short height)
+static int
+armada_drm_get_fmt_info(const struct armada_format *fmt,
+ uint32_t *pitch, uint32_t *offset, short width, short height)
{
+ const XF86ImageRec *img = &fmt->xv_image;
int ret = 0;
if (img->id == FOURCC_XVBO) {
@@ -184,7 +256,7 @@ static int armada_drm_ovl_set_img_info(const XF86ImageRec *img,
offset[0] = 0;
ret = pitch[0];
} else if (img->format == XvPlanar) {
- int size[3];
+ uint32_t size[3];
pitch[0] = width / img->horz_y_period;
pitch[1] = width / img->horz_u_period;
@@ -206,52 +278,228 @@ static int armada_drm_ovl_set_img_info(const XF86ImageRec *img,
return ret;
}
-static void armada_drm_ovl_bo_free(struct drm_xv *drmxv)
+static void
+armada_drm_coords_to_box(BoxPtr box, short x, short y, short w, short h)
+{
+ box->x1 = x;
+ box->y1 = y;
+ box->x2 = x + w;
+ box->y2 = y + h;
+}
+
+static void armada_drm_bufs_free(struct drm_xv *drmxv)
{
- int i;
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(drmxv->bufs); i++) {
+ if (drmxv->bufs[i].fb_id) {
+ if (drmxv->bufs[i].fb_id == drmxv->plane_fb_id)
+ drmxv->plane_fb_id = 0;
+ drmModeRmFB(drmxv->drm->fd, drmxv->bufs[i].fb_id);
+ drmxv->bufs[i].fb_id = 0;
+ }
+ if (drmxv->bufs[i].bo) {
+ drm_armada_bo_put(drmxv->bufs[i].bo);
+ drmxv->bufs[i].bo = NULL;
+ }
+ drmxv->bufs[i].phys = INVALID_PHYS;
+ }
+
+ if (drmxv->plane_fb_id) {
+ drmModeRmFB(drmxv->drm->fd, drmxv->plane_fb_id);
+ drmxv->plane_fb_id = 0;
+ }
+}
- for (i = 0; i < ARRAY_SIZE(drmxv->bo); i++)
- if (drmxv->bo[i]) {
- drm_armada_bo_put(drmxv->bo[i]);
- drmxv->bo[i] = NULL;
+static int armada_drm_bufs_alloc(struct drm_xv *drmxv)
+{
+ struct drm_armada_bufmgr *bufmgr = drmxv->drm->bufmgr;
+ uint32_t width = drmxv->width;
+ uint32_t height = drmxv->image_size / width / 4;
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(drmxv->bufs); i++) {
+ struct drm_armada_bo *bo;
+
+ bo = drm_armada_bo_dumb_create(bufmgr, width, height, 32);
+ drmxv->bufs[i].bo = bo;
+ if (!bo || drm_armada_bo_map(bo)) {
+ armada_drm_bufs_free(drmxv);
+ return BadAlloc;
}
+ }
+
+ return Success;
}
-static struct drm_armada_bo *armada_drm_ovl_get_bo(struct drm_xv *drmxv,
- size_t size, size_t width)
+/*
+ * Marvell BMM hack handling. This is pretty disgusting - it passes
+ * the physical address of the buffer via the Xv image interface, with
+ * a magic number, and a checksum.
+ */
+#define BMM_SHM_MAGIC1 0x13572468
+#define BMM_SHM_MAGIC2 0x24681357
+
+static uint32_t armada_drm_bmm_chk(unsigned char *buf, uint32_t len)
+{
+ uint32_t i, chk, *ptr = (uint32_t *)buf;
+
+ for (chk = i = 0; i < len; i++)
+ chk ^= ptr[i];
+
+ return chk;
+}
+
+static Bool armada_drm_is_bmm(unsigned char *buf)
+{
+ uint32_t *ptr, len;
+
+ if ((uintptr_t)buf & (sizeof(*ptr) - 1))
+ return FALSE;
+
+ ptr = (uint32_t *)buf;
+ if (*ptr != BMM_SHM_MAGIC1)
+ return FALSE;
+
+ len = 2 + ptr[1];
+ return armada_drm_bmm_chk(buf, len) == ptr[len];
+}
+
+static phys_t armada_drm_bmm_getbuf(unsigned char *buf)
+{
+ uint32_t *ptr, len;
+
+ if ((uintptr_t)buf & (sizeof(*ptr) - 1))
+ return INVALID_PHYS;
+
+ ptr = (uint32_t *)buf;
+ if (*ptr != BMM_SHM_MAGIC1)
+ return INVALID_PHYS;
+
+ len = 2 + ptr[1];
+ if (armada_drm_bmm_chk(buf, len) != ptr[len])
+ return INVALID_PHYS;
+
+ return ptr[2];
+}
+
+static void armada_drm_bmm_putbuf(unsigned char *buf, phys_t phys)
+{
+ uint32_t *ptr = (uint32_t *)buf;
+
+ *ptr++ = BMM_SHM_MAGIC2;
+ *ptr++ = 1;
+ *ptr++ = phys;
+ *ptr = armada_drm_bmm_chk(buf, 3);
+}
+
+static struct drm_armada_bo *
+armada_drm_get_bmm(struct drm_xv *drmxv, unsigned char *buf, uint32_t *id)
{
- struct armada_drm_info *drm = drmxv->drm;
struct drm_armada_bo *bo;
+ unsigned idx = drmxv->bo_idx;
+ phys_t phys;
- bo = drm_armada_bo_dumb_create(drm->bufmgr, width, size / width / 4, 32);
- if (bo && drm_armada_bo_map(bo)) {
- drm_armada_bo_put(bo);
- bo = NULL;
+ /* Marvell Dove special protocol */
+ phys = armada_drm_bmm_getbuf(buf);
+ if (phys == INVALID_PHYS)
+ return NULL;
+
+ if (idx == 0)
+ idx = ARRAY_SIZE(drmxv->bufs);
+ idx -= 1;
+ if (drmxv->bufs[idx].phys == phys) {
+ /* Re-display of previous frame */
+ if (id)
+ *id = drmxv->plane_fb_id;
+ drmxv->bo_idx = idx;
+ return (void *)1;
+ }
+
+ /* Map the passed buffer into a bo */
+ bo = drm_armada_bo_create_phys(drmxv->drm->bufmgr, phys, drmxv->image_size);
+ if (bo) {
+ phys_t old;
+
+ /* Return the now unused phys buffer */
+ old = drmxv->bufs[drmxv->bo_idx].phys;
+ if (old != INVALID_PHYS)
+ armada_drm_bmm_putbuf(buf, old);
+ drmxv->bufs[drmxv->bo_idx].phys = phys;
+ drmxv->bufs[drmxv->bo_idx].fb_id = 0;
}
+
return bo;
}
-static void armada_drm_ovl_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+static struct drm_armada_bo *
+armada_drm_get_xvbo(struct drm_xv *drmxv, unsigned char *buf, uint32_t *id)
{
- struct drm_xv *drmxv = data;
- struct drm_armada_overlay_put_image arg;
- int ret;
+ return drm_armada_bo_create_from_name(drmxv->drm->bufmgr,
+ ((uint32_t *)buf)[1]);
+}
- RegionEmpty(&drmxv->clipBoxes);
+static struct drm_armada_bo *
+armada_drm_get_stdbo(struct drm_xv *drmxv, unsigned char *src, uint32_t *id)
+{
+ struct drm_armada_bo *bo;
- memset(&arg, 0, sizeof(arg));
- ret = drmIoctl(drmxv->drm->fd, DRM_IOCTL_ARMADA_OVERLAY_PUT_IMAGE, &arg);
- if (ret)
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "[drm] unable to stop overlay: %s\n", strerror(errno));
+ /* Standard XV protocol */
+ bo = drmxv->bufs[drmxv->bo_idx].bo;
+ if (bo) {
+ memcpy(bo->ptr, src, drmxv->image_size);
+ drm_armada_bo_get(bo);
- if (cleanup) {
- drmxv->image = NULL;
- armada_drm_ovl_bo_free(drmxv);
+ if (id)
+ *id = drmxv->bufs[drmxv->bo_idx].fb_id;
+ }
+
+ return bo;
+}
+
+#ifdef LEGACY_OVERLAY
+static struct drm_armada_bo *
+armada_drm_get_cvtbo(struct drm_xv *drmxv, unsigned char *src)
+{
+ struct drm_armada_bo *bo;
+
+ /* Standard XV protocol */
+ bo = drmxv->bufs[drmxv->bo_idx].bo;
+ if (bo) {
+ /* Convert YV12 to YV16 or I420 to I422 */
+ unsigned char *dst = bo->ptr;
+ size_t size = drmxv->offsets[1];
+ int i;
+
+ /* Copy Y */
+ memcpy(dst, src, size);
+
+ dst += size;
+ src += size;
+
+ /* Copy U and V, doubling the number of pixels vertically */
+ size = drmxv->pitches[1];
+ for (i = drmxv->height; i > 0; i--) {
+ memcpy(dst, src, size);
+ dst += size;
+ memcpy(dst, src, size);
+ dst += size;
+ src += size;
+ }
+
+ drm_armada_bo_get(bo);
+
+ if (id)
+ *id = drmxv->bufs[drmxv->bo_idx].fb_id;
}
+ return bo;
}
+#endif
-static int armada_drm_ovl_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data)
+/* Common methods */
+static int
+armada_drm_Xv_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 value, pointer data)
{
struct drm_xv *drmxv = data;
Bool update_attrs = TRUE;
@@ -300,7 +548,8 @@ static int armada_drm_ovl_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, IN
return ret;
}
-static int armada_drm_ovl_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
+static int
+armada_drm_Xv_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 *value, pointer data)
{
struct drm_xv *drmxv = data;
@@ -338,7 +587,7 @@ static int armada_drm_ovl_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
return ret;
}
-static void armada_drm_ovl_QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
+static void armada_drm_Xv_QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
short vid_w, short vid_h, short drw_w, short drw_h,
unsigned int *p_w, unsigned int *p_h, pointer data)
{
@@ -349,164 +598,66 @@ static void armada_drm_ovl_QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
*p_h = maxt(vid_h, drw_h);
}
-#define BMM_SHM_MAGIC1 0x13572468
-#define BMM_SHM_MAGIC2 0x24681357
-
-static uint32_t armada_drm_bmm_chk(unsigned char *buf, uint32_t len)
-{
- uint32_t i, chk, *ptr = (uint32_t *)buf;
-
- for (chk = i = 0; i < len; i++)
- chk ^= ptr[i];
-
- return chk;
-}
-
-static Bool armada_drm_is_bmm(unsigned char *buf)
-{
- uint32_t *ptr, len;
-
- if ((uintptr_t)buf & (sizeof(*ptr) - 1))
- return FALSE;
-
- ptr = (uint32_t *)buf;
- if (*ptr != BMM_SHM_MAGIC1)
- return FALSE;
-
- len = 2 + ptr[1];
- return armada_drm_bmm_chk(buf, len) == ptr[len];
-}
-
-static phys_t armada_drm_bmm_getbuf(unsigned char *buf)
-{
- uint32_t *ptr, len;
-
- if ((uintptr_t)buf & (sizeof(*ptr) - 1))
- return (phys_t)-1;
-
- ptr = (uint32_t *)buf;
- if (*ptr != BMM_SHM_MAGIC1)
- return (phys_t)-1;
-
- len = 2 + ptr[1];
- if (armada_drm_bmm_chk(buf, len) != ptr[len])
- return (phys_t)-1;
-
- return ptr[2];
-}
-
-static void armada_drm_bmm_putbuf(unsigned char *buf, phys_t phys)
+static int
+armada_drm_Xv_QueryImageAttributes(ScrnInfoPtr pScrn, int image,
+ unsigned short *width, unsigned short *height, int *pitches,
+ int *offsets)
{
- uint32_t *ptr = (uint32_t *)buf;
+ const struct armada_format *fmt;
+ unsigned i, ret = 0;
+ uint32_t pitch[3], offset[3];
- *ptr++ = BMM_SHM_MAGIC2;
- *ptr++ = 1;
- *ptr++ = phys;
- *ptr = armada_drm_bmm_chk(buf, 3);
-}
-
-static int armada_drm_ovl_bmm(struct drm_xv *drmxv, unsigned char *buf, struct drm_armada_bo **pbo)
-{
- struct drm_armada_bo *old, *bo;
- phys_t phys;
-
- /* Marvell Dove special protocol */
- phys = armada_drm_bmm_getbuf(buf);
- if (phys == (phys_t)-1)
- return BadAlloc;
+ *width = (*width + 1) & ~1;
+ *height = (*height + 1) & ~1;
- /* Map the passed buffer into a bo */
- bo = drm_armada_bo_create_phys(drmxv->drm->bufmgr, phys, drmxv->image_size);
- if (!bo)
- return BadAlloc;
+ fmt = armada_drm_lookup_xvfourcc(image);
+ if (!fmt)
+ return 0;
- /* Free the old bo, and pass it back */
- old = drmxv->bo[drmxv->bo_idx];
- if (old) {
- drm_armada_bo_put(old);
- armada_drm_bmm_putbuf(buf, drmxv->bo_phys[drmxv->bo_idx]);
+ ret = armada_drm_get_fmt_info(fmt, pitch, offset, *width, *height);
+ if (ret) {
+ for (i = 0; i < fmt->xv_image.num_planes; i++) {
+ if (pitches)
+ pitches[i] = pitch[i];
+ if (offsets)
+ offsets[i] = offset[i];
+ }
}
- drmxv->bo[drmxv->bo_idx] = bo;
- drmxv->bo_phys[drmxv->bo_idx] = phys;
-
- *pbo = bo;
- drm_armada_bo_get(bo);
-
- return Success;
+ return ret;
}
-static int armada_drm_ovl_cvt(struct drm_xv *drmxv, unsigned char *src, struct drm_armada_bo **pbo)
+#ifdef LEGACY_OVERLAY
+static void
+armada_drm_ovl_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
{
- struct drm_armada_bo *bo;
- unsigned char *dst;
- size_t size;
- int i;
-
- /* Standard XV protocol */
- bo = drmxv->bo[drmxv->bo_idx];
- if (!bo)
- return BadAlloc;
-
- if (++drmxv->bo_idx >= ARRAY_SIZE(drmxv->bo))
- drmxv->bo_idx = 0;
-
- *pbo = bo;
-
- /* Convert YV12 to YV16 or I420 to I422 */
- dst = bo->ptr;
- size = drmxv->offsets[1];
+ struct drm_xv *drmxv = data;
+ struct drm_armada_overlay_put_image arg;
+ int ret;
- /* Copy Y */
- memcpy(dst, src, size);
+ RegionEmpty(&drmxv->clipBoxes);
- dst += size;
- src += size;
+ memset(&arg, 0, sizeof(arg));
+ ret = drmIoctl(drmxv->drm->fd, DRM_IOCTL_ARMADA_OVERLAY_PUT_IMAGE, &arg);
+ if (ret)
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "[drm] unable to stop overlay: %s\n", strerror(errno));
- /* Copy U and V, doubling the number of pixels vertically */
- size = drmxv->pitches[1];
- for (i = drmxv->image_height; i > 0; i--) {
- memcpy(dst, src, size);
- dst += size;
- memcpy(dst, src, size);
- dst += size;
- src += size;
+ if (cleanup) {
+ drmxv->image = NULL;
+ armada_drm_bufs_free(drmxv);
}
-
- drm_armada_bo_get(bo);
-
- return Success;
-}
-
-static int armada_drm_ovl_std(struct drm_xv *drmxv, unsigned char *src, struct drm_armada_bo **pbo)
-{
- struct drm_armada_bo *bo;
-
- /* Standard XV protocol */
- bo = drmxv->bo[drmxv->bo_idx];
- if (!bo)
- return BadAlloc;
-
- if (++drmxv->bo_idx >= ARRAY_SIZE(drmxv->bo))
- drmxv->bo_idx = 0;
-
- *pbo = bo;
-
- memcpy(bo->ptr, src, drmxv->image_size);
-
- drm_armada_bo_get(bo);
-
- return Success;
}
static int armada_drm_ovl_SetupStd(struct drm_xv *drmxv, int image,
short width, short height)
{
int i, size, image2 = image;
+ const struct armada_format *fmt;
const XF86ImageRec *img;
drmxv->image = NULL;
-
+#if 0
/*
* We can't actually do YV12 or I420 - we convert to YV16
* or YV16 with U and V swapped.
@@ -515,31 +666,26 @@ static int armada_drm_ovl_SetupStd(struct drm_xv *drmxv, int image,
image2 = FOURCC_YV16;
if (image2 == FOURCC_I420)
image2 = FOURCC_I422;
+#endif
/*
* Lookup the image type. Note that the server already did this in
* Xext/xvdisp.c, but xf86XVPutImage() in hw/xfree86/common/xf86xv.c
* threw that information away.
*/
- img = armada_drm_ovl_get_img(image2);
- if (!img)
+ fmt = armada_drm_lookup_xvfourcc(image);
+ if (!fmt)
return BadMatch;
- size = armada_drm_ovl_set_img_info(img, drmxv->pitches, drmxv->offsets,
- width, height);
+ size = armada_drm_get_fmt_info(fmt, drmxv->pitches, drmxv->offsets,
+ width, height);
if (!size)
return BadAlloc;
- drmxv->arg.flags = ARMADA_OVERLAY_ENABLE;
- if (img->type == XvYUV) {
- if (img->vert_u_period == 1)
- drmxv->arg.flags |= ARMADA_OVERLAY_YUV422;
- else
- drmxv->arg.flags |= ARMADA_OVERLAY_YUV420;
- }
+ drmxv->arg.flags = ARMADA_OVERLAY_ENABLE | fmt->flags;
+ img = &fmt->xv_image;
if (img->format == XvPlanar) {
- drmxv->arg.flags |= ARMADA_OVERLAY_YUV_PLANAR;
for (i = 0; i < img->num_planes; i++) {
switch (img->component_order[i]) {
case 'Y':
@@ -557,113 +703,83 @@ static int armada_drm_ovl_SetupStd(struct drm_xv *drmxv, int image,
}
}
} else {
- drmxv->arg.flags |= ARMADA_OVERLAY_YUV_PACKED;
drmxv->arg.offset_Y = drmxv->offsets[0];
drmxv->arg.offset_U = drmxv->offsets[0];
drmxv->arg.offset_V = drmxv->offsets[0];
drmxv->arg.stride_Y = drmxv->pitches[0];
drmxv->arg.stride_UV = drmxv->pitches[0];
-
- switch (image) {
- case FOURCC_VYUY:
- drmxv->arg.flags |= ARMADA_OVERLAY_UV_SWAP;
- case FOURCC_UYVY:
- drmxv->arg.flags |= ARMADA_OVERLAY_Y_SWAP;
- case FOURCC_YUY2:
- break;
- default:
- return BadAlloc;
- }
}
- armada_drm_ovl_bo_free(drmxv);
+ armada_drm_bufs_free(drmxv);
+
+ drmxv->image_size = size;
+ drmxv->width = width;
+ drmxv->height = height;
+ drmxv->fourcc = image;
+
+ if (!drmxv->is_bmm) {
+ int ret;
- if (drmxv->is_bmm) {
- drmxv->cvt = armada_drm_ovl_bmm;
- } else {
if (image != image2)
- drmxv->cvt = armada_drm_ovl_cvt;
+ drmxv->get_bo = armada_drm_get_cvtbo;
else
- drmxv->cvt = armada_drm_ovl_std;
+ drmxv->get_bo = armada_drm_get_stdbo;
- for (i = 0; i < ARRAY_SIZE(drmxv->bo); i++) {
- drmxv->bo[i] = armada_drm_ovl_get_bo(drmxv, size, width);
- if (!drmxv->bo[i]) {
- armada_drm_ovl_bo_free(drmxv);
- return BadAlloc;
- }
- }
+ ret = armada_drm_bufs_alloc(drmxv);
+ if (ret != Success)
+ return ret;
}
drmxv->image = img;
- drmxv->image_size = size;
- drmxv->image_width = width;
- drmxv->image_height = height;
- drmxv->image_fourcc = image;
return Success;
}
-static int armada_drm_ovl_clip(ScrnInfoPtr pScrn, struct drm_xv *drmxv,
- short src_x, short src_y, short drw_x, short drw_y,
- short src_w, short src_h, short drw_w, short drw_h,
- RegionPtr clipBoxes, short width, short height, xf86CrtcPtr *crtcp)
+static int armada_drm_ovl_Put(ScrnInfoPtr pScrn, struct drm_xv *drmxv,
+ short src_x, short src_y, short src_w, short src_h,
+ short width, short height, BoxPtr dst, RegionPtr clipBoxes)
{
- struct armada_crtc_info *drmc;
xf86CrtcPtr crtc = NULL;
- INT32 xa, xb, ya, yb;
- short src_sw, src_sh;
- BoxRec dst;
-
- xa = src_x;
- xb = src_x + src_w;
- ya = src_y;
- yb = src_y + src_h;
+ INT32 x1, x2, y1, y2;
- dst.x1 = drw_x;
- dst.x2 = drw_x + drw_w;
- dst.y1 = drw_y;
- dst.y2 = drw_y + drw_h;
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
if (!xf86_crtc_clip_video_helper(pScrn, &crtc, drmxv->desired_crtc,
- &dst, &xa, &xb, &ya, &yb, clipBoxes,
+ dst, &x1, &x2, &y1, &y2, clipBoxes,
width, height))
return BadAlloc;
- *crtcp = crtc;
-
- if (!crtc)
+ if (!crtc) {
+ armada_drm_ovl_StopVideo(pScrn, drmxv, TRUE);
return Success;
-
- src_sw = width * ((float)(dst.x2 - dst.x1) / drw_w);
- src_sh = height * ((float)(dst.y2 - dst.y1) / drw_h);
-
- /* Convert to coordinates on this CRTC. */
- drw_w = dst.x2 - dst.x1;
- drw_h = dst.y2 - dst.y1;
- drw_x = dst.x1 - crtc->x;
- drw_y = dst.y1 - crtc->y;
-
-{
- static int dx, dy, dw, dh, sow, soh, ssw, ssh;
- if (dx != drw_x || dy != drw_y || dw != drw_w || dh != drw_h || sow != width || soh != height || ssw != src_sw || ssh != src_sh) {
- dx = drw_x; dy = drw_y; dw = drw_w; dh = drw_h; sow = width; soh = height; ssw = src_sw; ssh = src_sh;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "os[%dx%d] ss[%dx%d] dst[%d,%d %dx%d]\n",
- sow, soh, ssw, ssh, dx, dy, dw, dh);
- }
-}
-
- drmc = crtc->driver_private;
+ }
drmxv->arg.src_width = width;
drmxv->arg.src_height = height;
- drmxv->arg.src_scan_width = src_sw;
- drmxv->arg.src_scan_height = src_sh;
- drmxv->arg.crtc_id = drmc->mode_crtc->crtc_id;
- drmxv->arg.dst_x = drw_x;
- drmxv->arg.dst_y = drw_y;
- drmxv->arg.dst_width = drw_w;
- drmxv->arg.dst_height = drw_h;
+ drmxv->arg.src_scan_width = x2 - x1;
+ drmxv->arg.src_scan_height = y2 - y1;
+ drmxv->arg.crtc_id = armada_crtc(crtc)->mode_crtc->crtc_id;
+ drmxv->arg.dst_x = dst->x1 - crtc->x;
+ drmxv->arg.dst_y = dst->y1 - crtc->y;
+ drmxv->arg.dst_width = dst->x2 - dst->x1;
+ drmxv->arg.dst_height = dst->y2 - dst->y1;
+
+ drmIoctl(drmxv->drm->fd, DRM_IOCTL_ARMADA_OVERLAY_PUT_IMAGE,
+ &drmxv->arg);
+
+ /*
+ * Finally, fill the clip boxes; do this after we've done the ioctl
+ * so we don't impact on latency.
+ */
+ if (drmxv->autopaint_colorkey &&
+ !RegionEqual(&drmxv->clipBoxes, clipBoxes)) {
+ RegionCopy(&drmxv->clipBoxes, clipBoxes);
+ xf86XVFillKeyHelper(pScrn->pScreen, drmxv->attrs.color_key,
+ clipBoxes);
+ }
return Success;
}
@@ -674,93 +790,362 @@ static int armada_drm_ovl_PutImage(ScrnInfoPtr pScrn,
int image, unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
{
- xf86CrtcPtr crtc = NULL;
struct drm_xv *drmxv = data;
struct drm_armada_bo *bo;
+ BoxRec dst;
+ Bool is_bo;
int ret;
-// xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-// "PutImage: s%dx%x+%d+%d d%dx%d+%d+%d image %x %dx%d sync %u\n",
-// src_w, src_h, src_x, src_y, drw_w, drw_h, drw_x, drw_y,
-// image, width, height, sync);
-
- ret = armada_drm_ovl_clip(pScrn, drmxv, src_x, src_y, drw_x, drw_y,
- src_w, src_h, drw_w, drw_h, clipBoxes,
- width, height, &crtc);
- if (ret != Success)
- return ret;
+ /* Lock out overlay if plane overlay is in use */
+ if (drmxv->plane_format)
+ return BadAlloc;
- if (!crtc) {
- armada_drm_ovl_StopVideo(pScrn, data, TRUE);
- return Success;
- }
+ armada_drm_coords_to_box(&dst, drw_x, drw_y, drw_w, drw_h);
- if (image == FOURCC_XVBO) {
- /* XVBO support allows applications to prepare the DRM buffer
+ is_bo = image == FOURCC_XVBO;
+ if (is_bo)
+ /*
+ * XVBO support allows applications to prepare the DRM buffer
* object themselves, and pass a global name to the X server to
* update the hardware with. This is similar to Intel XvMC
* support, except we also allow the image format to be
* specified via a fourcc as the first word.
*/
- uint32_t *p = (uint32_t *)buf;
- uint32_t fmt = p[0];
- uint32_t name = p[1];
+ image = ((uint32_t *)buf)[0];
+
+ if (!drmxv->image || drmxv->fourcc != image ||
+ drmxv->width != width || drmxv->height != height) {
+ if (is_bo) {
+ drmxv->is_bmm = TRUE;
+ drmxv->get_bo = armada_drm_get_xvbo;
+ } else if (armada_drm_is_bmm(buf)) {
+ drmxv->is_bmm = TRUE;
+ drmxv->get_bo = armada_drm_get_bmm;
+ } else {
+ drmxv->is_bmm = FALSE;
+ }
- if (!drmxv->image || drmxv->image_fourcc != fmt ||
- drmxv->image_width != width ||
- drmxv->image_height != height) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "[drm] XVBO: fourcc %08x name %08x\n",
- fmt, name);
- drmxv->is_bmm = 1;
- ret = armada_drm_ovl_SetupStd(drmxv, fmt, width, height);
- if (ret != Success) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] XVBO: SetupStd failed: %d\n", ret);
- return ret;
- }
+ ret = armada_drm_ovl_SetupStd(drmxv, image, width, height);
+ if (ret != Success) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] Xv: SetupStd failed: %d\n", ret);
+ return ret;
}
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "[drm] bmm %u xvbo %u fourcc %08x flags %08x\n",
+ drmxv->is_bmm, is_bo, image, drmxv->arg.flags);
+ }
+
+ bo = drmxv->get_bo(drmxv, buf, NULL);
+ if (!bo) {
+ uint32_t *p = (uint32_t *)buf;
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] Xv: failed to get buffer %08x %08x %08x %08x\n",
+ p[0], p[1], p[2], p[3]);
+ return BadAlloc;
+ }
+
+ if (++drmxv->bo_idx >= ARRAY_SIZE(drmxv->bufs))
+ drmxv->bo_idx = 0;
+
+ drmxv->arg.bo_handle = bo->handle;
+
+ ret = armada_drm_ovl_Put(pScrn, drmxv, src_x, src_y, src_w, src_h,
+ width, height, &dst, clipBoxes);
+
+ /*
+ * The kernel will keep a reference internally to
+ * the buffer object while it is being displayed.
+ */
+ drm_armada_bo_put(bo);
+
+ return ret;
+}
+
+static int armada_drm_ovl_ReputImage(ScrnInfoPtr pScrn,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
+{
+ struct drm_xv *drmxv = data;
+ BoxRec dst;
+
+ if (!drmxv->image)
+ return Success;
+
+ armada_drm_coords_to_box(&dst, drw_x, drw_y, drw_w, drw_h);
+
+ return armada_drm_ovl_Put(pScrn, drmxv, src_x, src_y, src_w, src_h,
+ drmxv->width, drmxv->height,
+ &dst, clipBoxes);
+}
+
+static XF86VideoAdaptorPtr
+armada_drm_XvInitOverlay(ScrnInfoPtr pScrn, DevUnion *priv)
+{
+ XF86VideoAdaptorPtr p;
+ XF86ImageRec *images;
+ unsigned i, num_images = ARRAY_SIZE(armada_drm_formats);
+
+ p = xf86XVAllocateVideoAdaptorRec(pScrn);
+ if (!p)
+ return NULL;
+
+ images = calloc(num_images, sizeof(*images));
+ if (!images) {
+ free(p);
+ return NULL;
+ }
+
+ for (i = 0; i < num_images; i++)
+ images[i] = armada_drm_formats[i].xv_image;
+
+ p->type = XvWindowMask | XvInputMask | XvImageMask;
+ p->flags = VIDEO_OVERLAID_IMAGES;
+ p->name = "Marvell Armada Overlay Video";
+ p->nEncodings = sizeof(OverlayEncodings) / sizeof(XF86VideoEncodingRec);
+ p->pEncodings = OverlayEncodings;
+ p->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec);
+ p->pFormats = OverlayFormats;
+ p->nPorts = 1;
+ p->pPortPrivates = priv;
+ p->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec);
+ p->pAttributes = OverlayAttributes;
+ p->nImages = num_images;
+ p->pImages = images;
+ p->StopVideo = armada_drm_ovl_StopVideo;
+ p->SetPortAttribute = armada_drm_Xv_SetPortAttribute;
+ p->GetPortAttribute = armada_drm_Xv_GetPortAttribute;
+ p->QueryBestSize = armada_drm_Xv_QueryBestSize;
+ p->PutImage = armada_drm_ovl_PutImage;
+ p->ReputImage = armada_drm_ovl_ReputImage;
+ p->QueryImageAttributes = armada_drm_Xv_QueryImageAttributes;
+
+ return p;
+}
+#endif
+
+/* Plane interface support */
+static int
+armada_drm_plane_fbid(ScrnInfoPtr pScrn, struct drm_xv *drmxv, int image,
+ unsigned char *buf, short width, short height, uint32_t *id)
+{
+ const struct armada_format *fmt;
+ struct drm_armada_bo *bo;
+ Bool is_bo = image == FOURCC_XVBO;
+
+ if (is_bo)
/*
- * Convert the global name back to a buffer object, so we have
- * a handle to pass to the kernel.
+ * XVBO support allows applications to prepare the DRM
+ * buffer object themselves, and pass a global name to
+ * the X server to update the hardware with. This is
+ * similar to Intel XvMC support, except we also allow
+ * the image format to be specified via a fourcc as the
+ * first word.
*/
- bo = drm_armada_bo_create_from_name(drmxv->drm->bufmgr, name);
- if (!bo) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "[drm] XVBO: bo_create_from_name failed: %d\n", ret);
- return BadAlloc;
+ image = ((uint32_t *)buf)[0];
+
+ if (drmxv->width != width || drmxv->height != height ||
+ drmxv->fourcc != image || !drmxv->plane_format) {
+ uint32_t size;
+
+ /* format or size changed */
+ fmt = armada_drm_lookup_xvfourcc(image);
+ if (!fmt)
+ return BadMatch;
+
+ /* Check whether this is XVBO mapping */
+ if (is_bo) {
+ drmxv->is_bmm = TRUE;
+ drmxv->get_bo = armada_drm_get_xvbo;
+ } else if (armada_drm_is_bmm(buf)) {
+ drmxv->is_bmm = TRUE;
+ drmxv->get_bo = armada_drm_get_bmm;
+ } else {
+ drmxv->is_bmm = FALSE;
+ drmxv->get_bo = armada_drm_get_stdbo;
}
- } else {
- if (!drmxv->image || drmxv->image_fourcc != image)
- drmxv->is_bmm = armada_drm_is_bmm(buf);
- if (!drmxv->image || drmxv->image_fourcc != image ||
- drmxv->image_width != width || drmxv->image_height != height) {
- ret = armada_drm_ovl_SetupStd(drmxv, image, width, height);
+ armada_drm_bufs_free(drmxv);
+
+ size = armada_drm_get_fmt_info(fmt, drmxv->pitches,
+ drmxv->offsets, width, height);
+
+ drmxv->image_size = size;
+ drmxv->width = width;
+ drmxv->height = height;
+ drmxv->fourcc = image;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "[drm] bmm %u xvbo %u fourcc %08x\n",
+ drmxv->is_bmm, is_bo, image);
+
+ /* Pre-allocate the buffers if we aren't using XVBO or BMM */
+ if (!drmxv->is_bmm) {
+ uint32_t handles[3];
+ unsigned i;
+ int ret = armada_drm_bufs_alloc(drmxv);
if (ret != Success)
return ret;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "[drm] bmm %u image fourcc %08x flags %08x\n",
- drmxv->is_bmm, image, drmxv->arg.flags);
+ /* And create framebuffers for each of these handles */
+ for (i = 0; i < ARRAY_SIZE(drmxv->bufs); i++) {
+ handles[0] =
+ handles[1] =
+ handles[2] = drmxv->bufs[i].bo->handle;
+
+ if (drmModeAddFB2(drmxv->drm->fd, width, height,
+ fmt->drm_format, handles,
+ drmxv->pitches,
+ drmxv->offsets,
+ &drmxv->bufs[i].fb_id, 0)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] drmModeAddFB2 failed: %s\n",
+ strerror(errno));
+ return BadAlloc;
+ }
+ }
}
- ret = drmxv->cvt(drmxv, buf, &bo);
- if (ret != Success)
- return ret;
+ drmxv->plane_format = fmt;
}
- drmxv->arg.bo_handle = bo->handle;
+ bo = drmxv->get_bo(drmxv, buf, id);
+ if (!bo) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] Xv: failed to get buffer\n");
+ return BadAlloc;
+ }
- ret = drmIoctl(drmxv->drm->fd, DRM_IOCTL_ARMADA_OVERLAY_PUT_IMAGE,
- &drmxv->arg);
+ if (drmxv->is_bmm && *id == 0) {
+ uint32_t handles[3];
- /*
- * The kernel will keep a reference internally to the buffer object
- * while it is being displayed.
- */
- drm_armada_bo_put(bo);
+ /* Just set the three plane handles to be the same */
+ handles[0] =
+ handles[1] =
+ handles[2] = bo->handle;
+
+ /* Create the framebuffer object for this buffer */
+ if (drmModeAddFB2(drmxv->drm->fd, width, height,
+ drmxv->plane_format->drm_format, handles,
+ drmxv->pitches, drmxv->offsets, id, 0)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] XVBO: drmModeAddFB2 failed: %s\n",
+ strerror(errno));
+ return BadAlloc;
+ }
+
+ /*
+ * We're done with this buffer object. We can drop our
+ * reference to it as it is now bound to the framebuffer,
+ * which will keep its own refcount(s) on the buffer.
+ */
+ drm_armada_bo_put(bo);
+ }
+
+ /* Move to the next buffer index now */
+ if (++drmxv->bo_idx >= ARRAY_SIZE(drmxv->bufs))
+ drmxv->bo_idx = 0;
+
+ return Success;
+}
+
+static void
+armada_drm_plane_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+{
+ struct drm_xv *drmxv = data;
+
+ if (drmxv->plane) {
+ int ret;
+
+ RegionEmpty(&drmxv->clipBoxes);
+
+ ret = drmModeSetPlane(drmxv->drm->fd, drmxv->plane->plane_id,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (ret)
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "[drm] unable to stop overlay: %s\n",
+ strerror(errno));
+ }
+
+ if (cleanup) {
+ drmxv->plane_format = NULL;
+ armada_drm_bufs_free(drmxv);
+ }
+}
+
+static Bool armada_drm_check_plane(ScrnInfoPtr pScrn, struct drm_xv *drmxv,
+ xf86CrtcPtr crtc)
+{
+ drmModePlanePtr plane;
+ uint32_t crtc_mask;
+
+ if (!crtc) {
+ /* Not being displayed on a CRTC */
+ armada_drm_plane_StopVideo(pScrn, drmxv, TRUE);
+ return FALSE;
+ }
+
+ crtc_mask = 1 << armada_crtc(crtc)->num;
+
+ plane = drmxv->plane;
+ if (plane && !(plane->possible_crtcs & crtc_mask)) {
+ /* Moved on to a different CRTC */
+ armada_drm_plane_StopVideo(pScrn, drmxv, FALSE);
+ plane = NULL;
+ }
+
+ if (!plane) {
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(drmxv->planes); i++)
+ if (drmxv->planes[i] &&
+ drmxv->planes[i]->possible_crtcs & crtc_mask)
+ plane = drmxv->planes[i];
+
+ /* Our new plane */
+ drmxv->plane = plane;
+
+ if (!plane)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+armada_drm_plane_Put(ScrnInfoPtr pScrn, struct drm_xv *drmxv, uint32_t fb_id,
+ short src_x, short src_y, short src_w, short src_h,
+ short width, short height, BoxPtr dst, RegionPtr clipBoxes)
+{
+ drmModePlanePtr plane;
+ xf86CrtcPtr crtc = NULL;
+ uint32_t crtc_x, crtc_y;
+ INT32 x1, x2, y1, y2;
+
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ if (!xf86_crtc_clip_video_helper(pScrn, &crtc, drmxv->desired_crtc,
+ dst, &x1, &x2, &y1, &y2, clipBoxes,
+ width, height))
+ return BadAlloc;
+
+ if (!armada_drm_check_plane(pScrn, drmxv, crtc))
+ return Success;
+
+ /* Calculate the position on this CRTC */
+ crtc_x = dst->x1 - crtc->x;
+ crtc_y = dst->y1 - crtc->y;
+
+ plane = drmxv->plane;
+ drmModeSetPlane(drmxv->drm->fd, plane->plane_id,
+ armada_crtc(crtc)->mode_crtc->crtc_id, fb_id, 0,
+ crtc_x, crtc_y, dst->x2 - dst->x1, dst->y2 - dst->y1,
+ x1, y1, x2 - x1, y2 - y1);
/*
* Finally, fill the clip boxes; do this after we've done the ioctl
@@ -769,83 +1154,158 @@ static int armada_drm_ovl_PutImage(ScrnInfoPtr pScrn,
if (drmxv->autopaint_colorkey &&
!RegionEqual(&drmxv->clipBoxes, clipBoxes)) {
RegionCopy(&drmxv->clipBoxes, clipBoxes);
-
- xf86XVFillKeyHelper(pScrn->pScreen, drmxv->attrs.color_key, clipBoxes);
+ xf86XVFillKeyHelper(pScrn->pScreen, drmxv->attrs.color_key,
+ clipBoxes);
}
return Success;
}
-static int armada_drm_ovl_ReputImage(ScrnInfoPtr pScrn,
- short src_x, short src_y, short drw_x, short drw_y,
- short src_w, short src_h, short drw_w, short drw_h,
- RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
+static int armada_drm_plane_PutImage(ScrnInfoPtr pScrn,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ int image, unsigned char *buf, short width, short height,
+ Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
{
- xf86CrtcPtr crtc = NULL;
struct drm_xv *drmxv = data;
+ BoxRec dst;
+ uint32_t fb_id;
int ret;
- if (!drmxv->image)
- return Success;
+#ifdef LEGACY_OVERLAY
+ /* Lock out plane overlay if overlay is in use */
+ if (drmxv->image)
+ return BadAlloc;
+#endif
+ armada_drm_coords_to_box(&dst, drw_x, drw_y, drw_w, drw_h);
- ret = armada_drm_ovl_clip(pScrn, drmxv, src_x, src_y, drw_x, drw_y,
- src_w, src_h, drw_w, drw_h, clipBoxes,
- drmxv->image_width, drmxv->image_height, &crtc);
- if (ret)
+ ret = armada_drm_plane_fbid(pScrn, drmxv, image, buf, width, height,
+ &fb_id);
+ if (ret != Success)
return ret;
- if (!crtc) {
- armada_drm_ovl_StopVideo(pScrn, data, TRUE);
- return Success;
+ ret = armada_drm_plane_Put(pScrn, drmxv, fb_id,
+ src_x, src_y, src_w, src_h,
+ width, height, &dst, clipBoxes);
+
+ /* If there was a previous fb, release it. */
+ if (drmxv->is_bmm &&
+ drmxv->plane_fb_id && drmxv->plane_fb_id != fb_id) {
+ drmModeRmFB(drmxv->drm->fd, drmxv->plane_fb_id);
+ drmxv->plane_fb_id = 0;
}
- ret = drmIoctl(drmxv->drm->fd, DRM_IOCTL_ARMADA_OVERLAY_PUT_IMAGE,
- &drmxv->arg);
+ drmxv->plane_fb_id = fb_id;
- if (drmxv->autopaint_colorkey &&
- !RegionEqual(&drmxv->clipBoxes, clipBoxes)) {
- RegionCopy(&drmxv->clipBoxes, clipBoxes);
+ return ret;
+}
- xf86XVFillKeyHelper(pScrn->pScreen, drmxv->attrs.color_key, clipBoxes);
- }
+static int armada_drm_plane_ReputImage(ScrnInfoPtr pScrn,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
+{
+ struct drm_xv *drmxv = data;
+ BoxRec dst;
- return Success;
+ if (drmxv->plane_fb_id == 0)
+ return Success;
+
+ armada_drm_coords_to_box(&dst, drw_x, drw_y, drw_w, drw_h);
+
+ return armada_drm_plane_Put(pScrn, drmxv, drmxv->plane_fb_id,
+ src_x, src_y, src_w, src_h,
+ drmxv->width, drmxv->height,
+ &dst, clipBoxes);
}
-static int armada_drm_ovl_QueryImageAttributes(ScrnInfoPtr pScrn,
- int image, unsigned short *width, unsigned short *height,
- int *pitches, int *offsets)
+static XF86VideoAdaptorPtr
+armada_drm_XvInitPlane(ScrnInfoPtr pScrn, DevUnion *priv, struct drm_xv *drmxv)
{
- const XF86ImageRec *img;
- unsigned ret = 0;
+ XF86VideoAdaptorPtr p;
+ XF86ImageRec *images;
+ unsigned i, num_images;
- *width = (*width + 1) & ~1;
- *height = (*height + 1) & ~1;
+ p = xf86XVAllocateVideoAdaptorRec(pScrn);
+ if (!p)
+ return NULL;
+
+#if 0
+ images = calloc(ARRAY_SIZE(armada_drm_formats), sizeof(*images));
+ if (!images) {
+ free(p);
+ return NULL;
+ }
- img = armada_drm_ovl_get_img(image);
- if (img) {
- int pitch[3], offset[3];
+ for (num_images = i = 0; i < ARRAY_SIZE(armada_drm_formats); i++) {
+ unsigned j;
- ret = armada_drm_ovl_set_img_info(img, pitch, offset,
- *width, *height);
+ if (armada_drm_formats[i].drm_format == 0)
+ continue;
- if (ret) {
- if (pitches)
- memcpy(pitches, pitch, sizeof(*pitches) * img->num_planes);
- if (offsets)
- memcpy(offsets, offset, sizeof(*offsets) * img->num_planes);
+ for (j = 0; j < drmxv->planes[0]->count_formats; j++) {
+ if (armada_drm_formats[i].drm_format ==
+ drmxv->planes[0]->formats[j]) {
+ images[num_images++] = armada_drm_formats[i].xv_image;
+ }
}
}
- return ret;
+#else
+ images = calloc(drmxv->planes[0]->count_formats, sizeof(*images));
+ if (!images) {
+ free(p);
+ return NULL;
+ }
+
+ for (num_images = i = 0; i < drmxv->planes[0]->count_formats; i++) {
+ const struct armada_format *fmt;
+ uint32_t id = drmxv->planes[0]->formats[i];
+
+ if (id == 0)
+ continue;
+
+ fmt = armada_drm_lookup_drmfourcc(id);
+ if (fmt)
+ images[num_images++] = fmt->xv_image;
+ }
+#endif
+
+ p->type = XvWindowMask | XvInputMask | XvImageMask;
+ p->flags = VIDEO_OVERLAID_IMAGES;
+ p->name = "Marvell Armada Overlay Video Plane";
+ p->nEncodings = sizeof(OverlayEncodings) / sizeof(XF86VideoEncodingRec);
+ p->pEncodings = OverlayEncodings;
+ p->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec);
+ p->pFormats = OverlayFormats;
+ p->nPorts = 1;
+ p->pPortPrivates = priv;
+ p->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec);
+ p->pAttributes = OverlayAttributes;
+ p->nImages = num_images;
+ p->pImages = images;
+ p->StopVideo = armada_drm_plane_StopVideo;
+ p->SetPortAttribute = armada_drm_Xv_SetPortAttribute;
+ p->GetPortAttribute = armada_drm_Xv_GetPortAttribute;
+ p->QueryBestSize = armada_drm_Xv_QueryBestSize;
+ p->PutImage = armada_drm_plane_PutImage;
+ p->ReputImage = armada_drm_plane_ReputImage;
+ p->QueryImageAttributes = armada_drm_Xv_QueryImageAttributes;
+
+ return p;
}
Bool armada_drm_XvInit(ScrnInfoPtr pScrn)
{
ScreenPtr scrn = screenInfo.screens[pScrn->scrnIndex];
- XF86VideoAdaptorPtr xv[1], p;
struct armada_drm_info *drm = GET_DRM_INFO(pScrn);
+ XF86VideoAdaptorPtr xv[2], plane;
+#ifdef LEGACY_OVERLAY
+ XF86VideoAdapterPtr overlay;
+#endif
+ drmModePlaneResPtr res;
struct drm_xv *drmxv;
DevUnion priv[1];
+ unsigned i, num;
Bool ret;
if (!xvColorKey) {
@@ -858,50 +1318,95 @@ Bool armada_drm_XvInit(ScrnInfoPtr pScrn)
xvPipe = MAKE_ATOM("XV_PIPE");
}
+ /* FIXME: we leak this */
drmxv = calloc(1, sizeof *drmxv);
if (!drmxv)
return FALSE;
+ for (i = 0; i < ARRAY_SIZE(drmxv->bufs); i++)
+ drmxv->bufs[i].phys = INVALID_PHYS;
+
+ /* Get the plane resources and the overlay planes */
+ res = drmModeGetPlaneResources(drm->fd);
+ if (!res)
+ goto err_free;
+
+ /* Get all plane information */
+ for (i = 0; i < res->count_planes && i < ARRAY_SIZE(drmxv->planes); i++) {
+ uint32_t plane_id = res->planes[i];
+
+ drmxv->planes[i] = drmModeGetPlane(drm->fd, plane_id);
+ if (!drmxv->planes[i]) {
+ drmModeFreePlaneResources(res);
+ goto err_free;
+ }
+ }
+
+ /* Done with the plane resources */
+ drmModeFreePlaneResources(res);
+
drmxv->drm = drm;
drmxv->autopaint_colorkey = TRUE;
drmIoctl(drm->fd, DRM_IOCTL_ARMADA_OVERLAY_ATTRS, &drmxv->attrs);
- p = xf86XVAllocateVideoAdaptorRec(pScrn);
- if (!p) {
- free(drmxv);
- return FALSE;
+ for (i = 0; i < ARRAY_SIZE(drmxv->planes); i++) {
+ drmModePlanePtr plane = drmxv->planes[i];
+ unsigned j;
+
+ if (!plane)
+ continue;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Plane %u CRTC %u FB %u Possible CRTC %08x\n",
+ plane->plane_id, plane->crtc_id, plane->fb_id,
+ plane->possible_crtcs);
+ for (j = 0; j < plane->count_formats; j++) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ " Format %08x %.4s\n",
+ plane->formats[j],
+ (char *)&plane->formats[j]);
+ }
}
+ num = 0;
priv[0].ptr = drmxv;
+#ifdef LEGACY_OVERLAY
+ overlay = armada_drm_XvInitOverlay(pScrn, priv);
+ if (!overlay)
+ goto err_free;
- p->type = XvWindowMask | XvInputMask | XvImageMask;
- p->flags = VIDEO_OVERLAID_IMAGES;
- p->name = "Marvell Armada Overlay Video";
- p->nEncodings = sizeof(OverlayEncodings) / sizeof(XF86VideoEncodingRec);
- p->pEncodings = OverlayEncodings;
- p->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec);
- p->pFormats = OverlayFormats;
- p->nPorts = 1;
- p->pPortPrivates = priv;
- p->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec);
- p->pAttributes = OverlayAttributes;
- p->nImages = sizeof(OverlayImages) / sizeof(XF86ImageRec);
- p->pImages = OverlayImages;
- p->StopVideo = armada_drm_ovl_StopVideo;
- p->SetPortAttribute = armada_drm_ovl_SetPortAttribute;
- p->GetPortAttribute = armada_drm_ovl_GetPortAttribute;
- p->QueryBestSize = armada_drm_ovl_QueryBestSize;
- p->PutImage = armada_drm_ovl_PutImage;
- p->ReputImage = armada_drm_ovl_ReputImage;
- p->QueryImageAttributes = armada_drm_ovl_QueryImageAttributes;
+ xv[num++] = overlay;
+#endif
- xv[0] = p;
- ret = xf86XVScreenInit(scrn, xv, 1);
- free(p);
+ if (drmxv->planes[0]) {
+ plane = armada_drm_XvInitPlane(pScrn, priv, drmxv);
+ if (!plane) {
+#ifdef LEGACY_OVERLAY
+ free(overlay->pImages);
+ free(overlay);
+#endif
+ goto err_free;
+ }
+ xv[num++] = plane;
+ }
- if (!ret)
- free(drmxv);
+ ret = xf86XVScreenInit(scrn, xv, num);
- return ret;
+ for (i = 0; i < num; i++) {
+ if (xv[i]) {
+ free(xv[i]->pImages);
+ free(xv[i]);
+ }
+ }
+ if (!ret)
+ goto err_free;
+ return TRUE;
+
+ err_free:
+ for (i = 0; i < ARRAY_SIZE(drmxv->plane); i++)
+ if (drmxv->planes[i])
+ drmModeFreePlane(drmxv->planes[i]);
+ free(drmxv);
+ return FALSE;
}