[PATCH xf86-video-nouveau] add dri2video support

Rob Clark rob.clark at linaro.org
Tue Nov 15 14:49:49 PST 2011


From: Rob Clark <rob at ti.com>

TODO:
 + format advertised as I420 appears to actually be NV12
 + add non-fourcc format values for hw decode directly to VRAM
   mapped buffer (skip GART->VRAM move)
 + CSC_MATRIX and OSD support..
---
 src/nouveau_dri2.c    |  214 ++++++++++++++++++++++++++++-----
 src/nouveau_xv.c      |  324 +++++++++++++++++++++++++++++++++++++++----------
 src/nv30_xv_tex.c     |    4 +-
 src/nv40_xv_tex.c     |    4 +-
 src/nv50_xv.c         |    2 +-
 src/nv_accel_common.c |   11 ++
 src/nv_type.h         |    1 +
 src/nvc0_xv.c         |    2 +-
 8 files changed, 459 insertions(+), 103 deletions(-)

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index d14443f..445cd52 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -10,6 +10,10 @@
 #include "dri2.h"
 #endif
 
+// put these somewhere common..
+#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
+#define FOURCC_STR(str)    FOURCC(str[0], str[1], str[2], str[3])
+
 #if defined(DRI2) && DRI2INFOREC_VERSION >= 3
 struct nouveau_dri2_buffer {
 	DRI2BufferRec base;
@@ -22,19 +26,87 @@ nouveau_dri2_buffer(DRI2BufferPtr buf)
 	return (struct nouveau_dri2_buffer *)buf;
 }
 
-DRI2BufferPtr
-nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
-			   unsigned int format)
+static DRI2BufferPtr
+nouveau_dri2_create_buffer_2(DrawablePtr pDraw, unsigned int attachment,
+		   unsigned int format, PixmapPtr ppix)
 {
 	ScreenPtr pScreen = pDraw->pScreen;
 	NVPtr pNv = NVPTR(xf86Screens[pScreen->myNum]);
-	struct nouveau_dri2_buffer *nvbuf;
 	struct nouveau_pixmap *nvpix;
-	PixmapPtr ppix;
+	struct nouveau_dri2_buffer *nvbuf;
 
 	nvbuf = calloc(1, sizeof(*nvbuf));
-	if (!nvbuf)
+	if (!nvbuf) {
+		// XXX cleanup..
+		return NULL;
+	}
+
+	pNv->exa_force_cp = TRUE;
+	exaMoveInPixmap(ppix);
+	pNv->exa_force_cp = FALSE;
+
+	nvbuf->base.attachment = attachment;
+	nvbuf->base.pitch = ppix->devKind;
+	nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8;
+	nvbuf->base.driverPrivate = nvbuf;
+	nvbuf->base.format = format;
+	nvbuf->base.flags = 0;
+	nvbuf->ppix = ppix;
+
+	nvpix = nouveau_pixmap(ppix);
+	if (!nvpix || !nvpix->bo ||
+	    nouveau_bo_handle_get(nvpix->bo, &nvbuf->base.name)) {
+		pScreen->DestroyPixmap(nvbuf->ppix);
+		free(nvbuf);
 		return NULL;
+	}
+
+	return &nvbuf->base;
+
+}
+
+static DRI2BufferPtr
+nouveau_dri2_create_buffer_vid(DrawablePtr pDraw, unsigned int attachment,
+			   unsigned int format, unsigned int width, unsigned int height)
+{
+	ScreenPtr pScreen = pDraw->pScreen;
+	PixmapPtr ppix;
+	int bpp;
+
+	switch(format) {
+	case FOURCC('I','4','2','0'):
+	case FOURCC('Y','V','1','2'):
+		/* to avoid confusing CreatePixmap too much, call these 1cpp
+		 *  and 1.5x height
+		 */
+		bpp = 8;
+		height = ((height + 1) & ~1) * 3 / 2;
+		break;
+	case FOURCC('Y','U','Y','2'):
+	case FOURCC('U','Y','V','Y'):
+		bpp = 16;
+		break;
+	case FOURCC('R','G','B','3'):  /* depth=24, bpp=32 */
+	case 24:
+	case FOURCC('R','G','B','4'):  /* depth=32, bpp=32 */
+	case 32:
+		bpp = 32;
+		break;
+	default:
+		return NULL;
+	}
+
+	ppix = pScreen->CreatePixmap(pScreen, width, height, bpp, NOUVEAU_CREATE_PIXMAP_VIDEO);
+
+	return nouveau_dri2_create_buffer_2(pDraw, attachment, format, ppix);
+}
+
+DRI2BufferPtr
+nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
+			   unsigned int format)
+{
+	ScreenPtr pScreen = pDraw->pScreen;
+	PixmapPtr ppix;
 
 	if (attachment == DRI2BufferFrontLeft) {
 		if (pDraw->type == DRAWABLE_PIXMAP) {
@@ -59,27 +131,7 @@ nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
 					     usage_hint);
 	}
 
-	pNv->exa_force_cp = TRUE;
-	exaMoveInPixmap(ppix);
-	pNv->exa_force_cp = FALSE;
-
-	nvbuf->base.attachment = attachment;
-	nvbuf->base.pitch = ppix->devKind;
-	nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8;
-	nvbuf->base.driverPrivate = nvbuf;
-	nvbuf->base.format = format;
-	nvbuf->base.flags = 0;
-	nvbuf->ppix = ppix;
-
-	nvpix = nouveau_pixmap(ppix);
-	if (!nvpix || !nvpix->bo ||
-	    nouveau_bo_handle_get(nvpix->bo, &nvbuf->base.name)) {
-		pScreen->DestroyPixmap(nvbuf->ppix);
-		free(nvbuf);
-		return NULL;
-	}
-
-	return &nvbuf->base;
+	return nouveau_dri2_create_buffer_2(pDraw, attachment, format, ppix);
 }
 
 void
@@ -95,6 +147,13 @@ nouveau_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf)
 	free(nvbuf);
 }
 
+/* moveme: */
+int
+nouveau_put_texture_image(DrawablePtr pDraw, PixmapPtr srcPix, int id,
+		short src_x, short src_y, short drw_x, short drw_y,
+		short src_w, short src_h, short drw_w, short drw_h,
+		short width, short height);
+
 void
 nouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
 			 DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
@@ -332,6 +391,49 @@ fail:
 }
 
 static Bool
+nouveau_dri2_schedule_swap_vid(ClientPtr client, DrawablePtr draw,
+			   DRI2BufferPtr dst, DRI2BufferPtr src,
+			   BoxPtr b, DrawablePtr osd,
+			   CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
+			   DRI2SwapEventPtr func, void *data)
+{
+	ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+	PixmapPtr src_pix = nouveau_dri2_buffer(src)->ppix;
+	short width, height;
+	int ret;
+
+	width  = src_pix->drawable.width;
+	height = src_pix->drawable.height;
+
+	if (src->format == FOURCC_STR("I420") ||
+			src->format == FOURCC_STR("YV12")) {
+		/* undo the 'height *= 1.5' trick to recover real height */
+		height = (height * 2) / 3;
+	}
+
+	/* attempt to hijack some of the XV USE_TEXTURE code.. maybe not the
+	 * cleanest way, or even work on all cards, but just for proof of concept..
+	 *
+	 * XXX this probably won't work for RGB formats, at least not on all
+	 * chipset versions (like NV50).. probably want to use the CopyRegion
+	 * code path (or something similar?) for RGB??
+	 */
+	ret = nouveau_put_texture_image(draw, src_pix, src->format,
+			b->x1, b->y1, draw->x, draw->y,
+			b->x2 - b->x1, b->y2 - b->y1, draw->width, draw->height,
+			width, height);
+
+	if (ret != Success) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING, "blit failed: %d\n", ret);
+		return FALSE;
+	}
+
+	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+
+	return TRUE;
+}
+
+static Bool
 nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
 			   CARD64 target_msc, CARD64 divisor, CARD64 remainder)
 {
@@ -396,6 +498,37 @@ nouveau_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 	return TRUE;
 }
 
+#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static int
+nouveau_set_attribute(DrawablePtr pDraw, Atom attribute,
+		int len, const CARD32 *val)
+{
+	/* just for testing.. bogus colorspace conversion matrix.. */
+	if (attribute == ATOM("XV_CSC_MATRIX")) {
+		return Success;
+	}
+	return BadMatch;
+}
+
+static int
+nouveau_get_attribute(DrawablePtr pDraw, Atom attribute,
+		int *len, const CARD32 **val)
+{
+	/* just for testing.. bogus colorspace conversion matrix.. */
+	if (attribute == ATOM("XV_CSC_MATRIX")) {
+		static const CARD32 csc[] = {
+				0x00, 0x01, 0x02, 0x03,
+				0x10, 0x11, 0x12, 0x13,
+				0x20, 0x21, 0x22, 0x23,
+		};
+		*val = csc;
+		*len = sizeof(csc) / 4;
+		return Success;
+	}
+	return BadMatch;
+}
+
 void
 nouveau_dri2_vblank_handler(int fd, unsigned int frame,
 			    unsigned int tv_sec, unsigned int tv_usec,
@@ -428,28 +561,47 @@ nouveau_dri2_init(ScreenPtr pScreen)
 	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
 	NVPtr pNv = NVPTR(pScrn);
 	DRI2InfoRec dri2 = { 0 };
-	const char *drivernames[2][2] = {
-		{ "nouveau", "nouveau" },
-		{ "nouveau_vieux", "nouveau_vieux" }
+	const char *drivernames[2][3] = {
+		{ "nouveau", "nouveau", "nouveau" },
+		{ "nouveau_vieux", "nouveau_vieux", NULL }
+	};
+	const unsigned int formats[] = {
+			FOURCC_STR("YUY2"),
+			FOURCC_STR("YV12"),
+			FOURCC_STR("UYVY"),
+			FOURCC_STR("I420"),
+			FOURCC_STR("RGB3"),  /* depth=24, bpp=32 */
+			FOURCC_STR("RGB4"),  /* depth=32, bpp=32 */
+			/* non-common formats: */
+			// XXX check what might have been passed by mesa!!
+			24,
+			32,
 	};
 
 	if (pNv->Architecture >= NV_ARCH_30)
 		dri2.driverNames = drivernames[0];
 	else
 		dri2.driverNames = drivernames[1];
-	dri2.numDrivers = 2;
+	dri2.numDrivers = 3;
 	dri2.driverName = dri2.driverNames[0];
 
+	dri2.numFormats = ARRAY_SIZE(formats);
+	dri2.formats = formats;
+
 	dri2.fd = nouveau_device(pNv->dev)->fd;
 	dri2.deviceName = pNv->drm_device_name;
 
 	dri2.version = DRI2INFOREC_VERSION;
 	dri2.CreateBuffer = nouveau_dri2_create_buffer;
+	dri2.CreateBufferVid = nouveau_dri2_create_buffer_vid;
 	dri2.DestroyBuffer = nouveau_dri2_destroy_buffer;
 	dri2.CopyRegion = nouveau_dri2_copy_region;
 	dri2.ScheduleSwap = nouveau_dri2_schedule_swap;
+	dri2.ScheduleSwapVid = nouveau_dri2_schedule_swap_vid;
 	dri2.ScheduleWaitMSC = nouveau_dri2_schedule_wait;
 	dri2.GetMSC = nouveau_dri2_get_msc;
+	dri2.SetAttribute = nouveau_set_attribute;
+	dri2.GetAttribute = nouveau_get_attribute;
 
 	return DRI2ScreenInit(pScreen, &dri2);
 }
diff --git a/src/nouveau_xv.c b/src/nouveau_xv.c
index 5a5337c..2733a2c 100644
--- a/src/nouveau_xv.c
+++ b/src/nouveau_xv.c
@@ -561,6 +561,10 @@ NVCopyNV12ColorPlanes(unsigned char *src1, unsigned char *src2,
 }
 
 
+// put these somewhere common..
+#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
+#define FOURCC_STR(str)    FOURCC(str[0], str[1], str[2], str[3])
+
 static int
 NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 *xa, INT32 *xb,
 		  INT32 *ya, INT32 *yb, short *src_x, short *src_y,
@@ -887,6 +891,87 @@ NV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv,
 	}
 }
 
+/* move from GART -> VRAM */
+static int
+nouveau_xv_m2mf(ScrnInfoPtr pScrn, int action_flags,
+		struct nouveau_bo *src /* GART buffer */,
+		struct nouveau_bo *dst /* VRAM buffer */,
+		int offset, int uv_offset, int nlines, int line_len, int dstPitch)
+{
+	NVPtr pNv = NVPTR(pScrn);
+	struct nouveau_channel *chan = pNv->chan;
+	struct nouveau_grobj *m2mf = pNv->NvMemFormat;
+
+	if (pNv->Architecture >= NV_ARCH_C0) {
+		nvc0_xv_m2mf(m2mf, dst, uv_offset, dstPitch,
+			     nlines, src, line_len);
+		return Success;
+	}
+
+	if (MARK_RING(chan, 64, 4))
+		return BadAlloc;
+
+	BEGIN_RING(chan, m2mf,
+		   NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+	OUT_RING  (chan, pNv->chan->gart->handle);
+	OUT_RING  (chan, pNv->chan->vram->handle);
+
+	if (pNv->Architecture >= NV_ARCH_50) {
+		BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1);
+		OUT_RING  (chan, 1);
+
+		BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 7);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, src->tile_mode << 4);
+		OUT_RING  (chan, dstPitch);
+		OUT_RING  (chan, nlines);
+		OUT_RING  (chan, 1);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, 0);
+	}
+
+	/* DMA to VRAM */
+	if ( (action_flags & IS_YV12) &&
+	    !(action_flags & CONVERT_TO_YUY2)) {
+		/* we start the color plane transfer separately */
+
+		BEGIN_RING(chan, m2mf,
+			   NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+		if (OUT_RELOCl(chan, src,
+			       line_len * nlines,
+			       NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
+		    OUT_RELOCl(chan, dst,
+			       offset + uv_offset,
+			       NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
+			MARK_UNDO(chan);
+			return BadAlloc;
+		}
+		OUT_RING  (chan, line_len);
+		OUT_RING  (chan, dstPitch);
+		OUT_RING  (chan, line_len);
+		OUT_RING  (chan, (nlines >> 1));
+		OUT_RING  (chan, (1<<8)|1);
+		OUT_RING  (chan, 0);
+	}
+
+	BEGIN_RING(chan, m2mf,
+		   NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+	if (OUT_RELOCl(chan, src, 0,
+		       NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
+	    OUT_RELOCl(chan, dst, offset,
+		       NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
+		MARK_UNDO(chan);
+		return BadAlloc;
+	}
+	OUT_RING  (chan, line_len);
+	OUT_RING  (chan, dstPitch);
+	OUT_RING  (chan, line_len);
+	OUT_RING  (chan, nlines);
+	OUT_RING  (chan, (1<<8)|1);
+	OUT_RING  (chan, 0);
+
+	return Success;
+}
 
 /**
  * NVPutImage
@@ -936,8 +1021,6 @@ NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x,
 	 * and lines we are interested in
 	 */
 	int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0;
-	struct nouveau_channel *chan = pNv->chan;
-	struct nouveau_grobj *m2mf = pNv->NvMemFormat;
 	Bool skip = FALSE;
 	BoxRec dstBox;
 	CARD32 tmp = 0;
@@ -1111,73 +1194,17 @@ NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x,
 
 		nouveau_bo_unmap(destination_buffer);
 
-		if (pNv->Architecture >= NV_ARCH_C0) {
-			nvc0_xv_m2mf(m2mf, pPriv->video_mem, uv_offset, dstPitch,
-				     nlines, destination_buffer, line_len);
-			goto put_image;
-		}
-
-		if (MARK_RING(chan, 64, 4))
-			return FALSE;
-
-		BEGIN_RING(chan, m2mf,
-			   NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
-		OUT_RING  (chan, pNv->chan->gart->handle);
-		OUT_RING  (chan, pNv->chan->vram->handle);
-
-		if (pNv->Architecture >= NV_ARCH_50) {
-			BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1);
-			OUT_RING  (chan, 1);
-
-			BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 7);
-			OUT_RING  (chan, 0);
-			OUT_RING  (chan, destination_buffer->tile_mode << 4);
-			OUT_RING  (chan, dstPitch);
-			OUT_RING  (chan, nlines);
-			OUT_RING  (chan, 1);
-			OUT_RING  (chan, 0);
-			OUT_RING  (chan, 0);
-		}
-
-		/* DMA to VRAM */
-		if ( (action_flags & IS_YV12) &&
-		    !(action_flags & CONVERT_TO_YUY2)) {
-			/* we start the color plane transfer separately */
-
-			BEGIN_RING(chan, m2mf,
-				   NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-			if (OUT_RELOCl(chan, destination_buffer,
-				       line_len * nlines,
-				       NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
-			    OUT_RELOCl(chan, pPriv->video_mem,
-				       offset + uv_offset,
-				       NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
-				MARK_UNDO(chan);
-				return BadAlloc;
-			}
-			OUT_RING  (chan, line_len);
-			OUT_RING  (chan, dstPitch);
-			OUT_RING  (chan, line_len);
-			OUT_RING  (chan, (nlines >> 1));
-			OUT_RING  (chan, (1<<8)|1);
-			OUT_RING  (chan, 0);
+		ret = nouveau_xv_m2mf(pScrn, action_flags,
+				destination_buffer, pPriv->video_mem,
+				offset, uv_offset, nlines, line_len, dstPitch);
+		if (ret != Success) {
+			return ret;
 		}
 
-		BEGIN_RING(chan, m2mf,
-			   NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-		if (OUT_RELOCl(chan, destination_buffer, 0,
-			       NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
-		    OUT_RELOCl(chan, pPriv->video_mem, offset,
-			       NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
-			MARK_UNDO(chan);
-			return BadAlloc;
+		if (pNv->Architecture >= NV_ARCH_C0) {
+			/* is this needed?  It is to preserve the original code flow */
+			goto put_image;
 		}
-		OUT_RING  (chan, line_len);
-		OUT_RING  (chan, dstPitch);
-		OUT_RING  (chan, line_len);
-		OUT_RING  (chan, nlines);
-		OUT_RING  (chan, (1<<8)|1);
-		OUT_RING  (chan, 0);
 	} else {
 CPU_copy:
 		nouveau_bo_map(pPriv->video_mem, NOUVEAU_BO_WR);
@@ -1356,6 +1383,171 @@ put_image:
 	return Success;
 }
 
+int
+nouveau_put_texture_image(DrawablePtr pDraw, PixmapPtr srcPix, int id,
+		short src_x, short src_y, short drw_x, short drw_y,
+		short src_w, short src_h, short drw_w, short drw_h,
+		short width, short height)
+{
+	ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
+	NVPtr pNv = NVPTR(pScrn);
+	PixmapPtr dstPix = NVGetDrawablePixmap(pDraw);
+	BoxRec dstBox;
+	RegionRec clipRegion;
+	int action_flags;
+	struct nouveau_bo *src;
+	int ret = BadImplementation;
+
+	// XXX we just need pPriv->video_mem... maybe there is a better way?
+	NVPortPrivPtr pPriv = (NVPortPrivPtr)((pNv)->textureAdaptor[0]->pPortPrivates[0].ptr);
+
+	/* source box */
+	INT32 xa = 0, xb = 0, ya = 0, yb = 0;
+	/* size to allocate in VRAM and in GART respectively */
+	int newFBSize = 0, newTTSize = 0;  /* ignored */
+	/* card VRAM offsets, source offsets for U and V planes */
+	int offset = 0, uv_offset = 0, s2offset = 0, s3offset = 0;
+	/* source pitch, source pitch of U and V planes in case of YV12,
+	 * VRAM destination pitch
+	 */
+	int srcPitch = 0, srcPitch2 = 0, dstPitch = 0;
+	/* position of the given source data (using src_*), number of pixels
+	 * and lines we are interested in
+	 */
+	int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0;
+	/* length of a line, like npixels, but in bytes */
+	int line_len = 0;
+
+	RegionInit(&clipRegion, (&(BoxRec){ 0, 0, pDraw->width, pDraw->height }), 0);
+	RegionTranslate(&clipRegion, pDraw->x, pDraw->y);
+
+	action_flags = USE_TEXTURE;
+
+	switch(id) {
+	case FOURCC_YUY2:
+	case FOURCC_UYVY:
+		action_flags |= IS_YUY2;
+		break;
+	case FOURCC_I420:
+		action_flags |= SWAP_UV;
+		/* fallthrough */
+	case FOURCC_YV12:
+		action_flags |= IS_YV12;
+		break;
+	case FOURCC_RGB:
+	case FOURCC('R','G','B','4'):
+	case FOURCC('R','G','B','3'):
+		action_flags |= IS_RGB;
+		break;
+	default:
+		return BadColor;
+	}
+
+	if (NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb,
+			      &src_x,  &src_y, &src_w, &src_h,
+			      &drw_x, &drw_y, &drw_w, &drw_h,
+			      &left, &top, &right, &bottom, &dstBox,
+			      &npixels, &nlines, &clipRegion, width, height)) {
+		return Success;
+	}
+
+	/* note: in Xv code, pixel buffer is src, uploaded YUV data is dst
+	 * which becomes the src for the PutTextureImage() step.. so dstPitch
+	 * is really our srcPitch (of src pixmap) and srcPitch's are ignored..
+	 * as are a couple other things..
+	 */
+	if (NV_calculate_pitches_and_mem_size(pNv, action_flags, &srcPitch,
+					      &srcPitch2, &dstPitch, &s2offset,
+					      &s3offset, &uv_offset,
+					      &newFBSize, &newTTSize,
+					      &line_len, npixels, nlines,
+					      width, height)) {
+		return BadImplementation;
+	}
+
+	/* Ensure src and dst pixmap is in offscreen memory */
+	pNv->exa_force_cp = TRUE;
+	exaMoveInPixmap(dstPix);
+	exaMoveInPixmap(srcPix);
+	pNv->exa_force_cp = FALSE;
+
+	if (!exaGetPixmapDriverPrivate(dstPix) ||
+			!exaGetPixmapDriverPrivate(srcPix)) {
+		return BadAlloc;
+	}
+
+	src = nouveau_pixmap_bo(srcPix);
+
+#ifdef COMPOSITE
+	/* Convert screen coords to pixmap coords */
+	if (dstPix->screen_x || dstPix->screen_y) {
+		REGION_TRANSLATE(pScrn->pScreen, &clipRegion,
+				 -dstPix->screen_x, -dstPix->screen_y);
+		dstBox.x1 -= dstPix->screen_x;
+		dstBox.x2 -= dstPix->screen_x;
+		dstBox.y1 -= dstPix->screen_y;
+		dstBox.y2 -= dstPix->screen_y;
+	}
+#endif
+
+	/* TODO check if src buffer is already in VRAM.. for hw decode
+	 * we probably want to allow giving the client buffers in VRAM
+	 * directly (via non-fourcc format values)
+	 */
+
+	ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, newFBSize,
+				    &pPriv->video_mem);
+	if (ret)
+		return BadAlloc;
+
+	ret = nouveau_xv_m2mf(pScrn, action_flags, src, pPriv->video_mem,
+			offset, uv_offset, nlines, line_len, dstPitch);
+	if (ret != Success) {
+		return ret;
+	}
+
+	if (pNv->Architecture == NV_ARCH_30) {
+		ret = NV30PutTextureImage(pScrn, pPriv->video_mem,
+					  offset, uv_offset,
+					  id, dstPitch, &dstBox, 0, 0,
+					  xb, yb, npixels, nlines,
+					  src_w, src_h, drw_w, drw_h,
+					  &clipRegion, dstPix, NULL);
+	} else if (pNv->Architecture == NV_ARCH_40) {
+		ret = NV40PutTextureImage(pScrn, pPriv->video_mem,
+					  offset, uv_offset,
+					  id, dstPitch, &dstBox, 0, 0,
+					  xb, yb, npixels, nlines,
+					  src_w, src_h, drw_w, drw_h,
+					  &clipRegion, dstPix, NULL);
+	} else if (pNv->Architecture == NV_ARCH_50) {
+		ret = nv50_xv_image_put(pScrn, pPriv->video_mem,
+					offset, uv_offset,
+					id, dstPitch, &dstBox, 0, 0,
+					xb, yb, npixels, nlines,
+					src_w, src_h, drw_w, drw_h,
+					&clipRegion, dstPix, NULL);
+	} else {
+		ret = nvc0_xv_image_put(pScrn, pPriv->video_mem,
+					offset, uv_offset,
+					id, dstPitch, &dstBox, 0, 0,
+					xb, yb, npixels, nlines,
+					src_w, src_h, drw_w, drw_h,
+					&clipRegion, dstPix, NULL);
+	}
+
+#ifdef COMPOSITE
+	/* Damage tracking */
+	if (!(action_flags & USE_OVERLAY))
+		DamageDamageRegion(&dstPix->drawable, &clipRegion);
+#endif
+
+	RegionUninit(&clipRegion);
+
+	return ret;
+}
+
+
 /**
  * QueryImageAttributes
  *
diff --git a/src/nv30_xv_tex.c b/src/nv30_xv_tex.c
index 6d4e089..9c0e828 100644
--- a/src/nv30_xv_tex.c
+++ b/src/nv30_xv_tex.c
@@ -259,7 +259,7 @@ NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset,
 	struct nouveau_channel *chan = pNv->chan;
 	struct nouveau_grobj *rankine = pNv->Nv3D;
 	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
-	Bool bicubic = pPriv->bicubic;
+	Bool bicubic = pPriv && pPriv->bicubic;
 	float X1, X2, Y1, Y2;
 	BoxPtr pbox;
 	int nbox;
@@ -349,7 +349,7 @@ NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset,
 	}
 
 	/* Just before rendering we wait for vblank in the non-composited case. */
-	if (pPriv->SyncToVBlank) {
+	if (pPriv && pPriv->SyncToVBlank) {
 		FIRE_RING(chan);
 		NV11SyncToVBlank(ppix, dstBox);
 	}
diff --git a/src/nv40_xv_tex.c b/src/nv40_xv_tex.c
index 0910e12..6249faf 100644
--- a/src/nv40_xv_tex.c
+++ b/src/nv40_xv_tex.c
@@ -263,7 +263,7 @@ NV40PutTextureImage(ScrnInfoPtr pScrn,
 	struct nouveau_channel *chan = pNv->chan;
 	struct nouveau_grobj *curie = pNv->Nv3D;
 	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
-	Bool bicubic = pPriv->bicubic;
+	Bool bicubic = pPriv && pPriv->bicubic;
 	float X1, X2, Y1, Y2;
 	BoxPtr pbox;
 	int nbox;
@@ -338,7 +338,7 @@ NV40PutTextureImage(ScrnInfoPtr pScrn,
 	OUT_RING  (chan, 1);
 
 	/* Just before rendering we wait for vblank in the non-composited case. */
-	if (pPriv->SyncToVBlank) {
+	if (pPriv && pPriv->SyncToVBlank) {
 		FIRE_RING(chan);
 		NV11SyncToVBlank(ppix, dstBox);
 	}
diff --git a/src/nv50_xv.c b/src/nv50_xv.c
index ddeb5bb..8b6bd67 100644
--- a/src/nv50_xv.c
+++ b/src/nv50_xv.c
@@ -290,7 +290,7 @@ nv50_xv_image_put(ScrnInfoPtr pScrn,
 	if (!nv50_xv_state_emit(ppix, id, src, packed_y, uv, width, height))
 		return BadAlloc;
 
-	if (pPriv->SyncToVBlank) {
+	if (pPriv && pPriv->SyncToVBlank) {
 		NV50SyncToVBlank(ppix, dstBox);
 	}
 
diff --git a/src/nv_accel_common.c b/src/nv_accel_common.c
index 735f47f..7775331 100644
--- a/src/nv_accel_common.c
+++ b/src/nv_accel_common.c
@@ -30,6 +30,7 @@ nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, int bpp,
 	NVPtr pNv = NVPTR(scrn);
 	Bool scanout = (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT);
 	Bool tiled = (usage_hint & NOUVEAU_CREATE_PIXMAP_TILED);
+	Bool video = (usage_hint & NOUVEAU_CREATE_PIXMAP_VIDEO);
 	int tile_mode = 0, tile_flags = 0;
 	int flags = NOUVEAU_BO_MAP | (bpp >= 8 ? NOUVEAU_BO_VRAM : 0);
 	int cpp = bpp / 8, ret;
@@ -114,6 +115,16 @@ nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, int bpp,
 	if (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT)
 		tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
 
+	if (video) {
+		if (pNv->Architecture == NV_ARCH_50)
+			tile_flags = 0x7000;
+		else if (pNv->Architecture == NV_ARCH_C0)
+			tile_flags = 0xfe00;
+		tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
+		tile_mode = 0;
+		flags = NOUVEAU_BO_MAP | NOUVEAU_BO_GART;
+	}
+
 	ret = nouveau_bo_new_tile(pNv->dev, flags, 0, *pitch * height,
 				  tile_mode, tile_flags, bo);
 	if (ret)
diff --git a/src/nv_type.h b/src/nv_type.h
index 4204556..c73c156 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -156,6 +156,7 @@ typedef struct _NVPortPrivRec {
 #define NOUVEAU_CREATE_PIXMAP_ZETA	0x10000000
 #define NOUVEAU_CREATE_PIXMAP_TILED	0x20000000
 #define NOUVEAU_CREATE_PIXMAP_SCANOUT	0x40000000
+#define NOUVEAU_CREATE_PIXMAP_VIDEO	0x80000000
 
 struct nouveau_pixmap {
 	struct nouveau_bo *bo;
diff --git a/src/nvc0_xv.c b/src/nvc0_xv.c
index 41ec7a8..149eaaf 100644
--- a/src/nvc0_xv.c
+++ b/src/nvc0_xv.c
@@ -343,7 +343,7 @@ nvc0_xv_image_put(ScrnInfoPtr pScrn,
 	if (!nvc0_xv_state_emit(ppix, id, src, packed_y, uv, width, height))
 		return BadAlloc;
 
-	if (0 && pPriv->SyncToVBlank) {
+	if (0 && pPriv && pPriv->SyncToVBlank) {
 		NV50SyncToVBlank(ppix, dstBox);
 	}
 
-- 
1.7.5.4



More information about the xorg-devel mailing list