diff mbox

[3/3] XvMC: Hack up zero-copy bo passthrough to work with kms

Message ID 1516e4918929b0de22fce55fcab85092e0046760.1256562682.git.daniel.vetter@ffwll.ch (mailing list archive)
State Rejected
Headers show

Commit Message

Daniel Vetter Oct. 26, 2009, 1:15 p.m. UTC
None
diff mbox

Patch

diff --git a/src/i830_hwmc.c b/src/i830_hwmc.c
index 3471524..1d92731 100644
--- a/src/i830_hwmc.c
+++ b/src/i830_hwmc.c
@@ -55,7 +55,8 @@  Bool intel_xvmc_probe(ScrnInfoPtr scrn)
 	if (!intel->XvMCEnabled)
 		return FALSE;
 
-	/* Needs KMS support. */
+	/* Needs special KMS support.  Look for NEED_PHYSICAL_ADDR in
+	 * i915_hwmc.c to see why. */
 	if (IS_I915G(intel) || IS_I915GM(intel))
 		return FALSE;
 
diff --git a/src/i830_video.c b/src/i830_video.c
index 888e566..67fe024 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -969,6 +969,11 @@  I830CopyPlanarData(intel_adaptor_private *adaptor_priv,
 	       srcPitch, srcPitch2, dstPitch, h, w, top, left);
 #endif
 
+	if (adaptor_priv->xvmc_passthrough_buf) {
+		drm_intel_bo_map(adaptor_priv->xvmc_passthrough_buf, FALSE);
+		buf = adaptor_priv->xvmc_passthrough_buf->virtual;
+	}
+
 	/* Copy Y data */
 	src1 = buf + (top * srcPitch) + left;
 #if 0
@@ -1021,6 +1026,10 @@  I830CopyPlanarData(intel_adaptor_private *adaptor_priv,
 			  dstPitch, srcPitch2, adaptor_priv->rotation);
 
 	drm_intel_bo_unmap(adaptor_priv->buf);
+
+	if (adaptor_priv->xvmc_passthrough_buf) {
+		drm_intel_bo_unmap(adaptor_priv->xvmc_passthrough_buf);
+	}
 }
 
 static void i830_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
@@ -1166,10 +1175,10 @@  int is_planar_fourcc(int id)
 	}
 }
 
-static int xvmc_passthrough(int id)
+static int xvmc_passthrough(int id, Rotation rotation)
 {
 #ifdef INTEL_XVMC
-	return id == FOURCC_XVMC;
+	return id == FOURCC_XVMC && rotation == RR_Rotate_0;
 #else
 	return 0;
 #endif
@@ -1332,7 +1341,7 @@  i830_wait_for_scanline(ScrnInfoPtr scrn, PixmapPtr pixmap,
 
 static Bool
 i830_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
-			int alloc_size, int id, unsigned char *buf)
+			int alloc_size, int id)
 {
 	intel_screen_private *intel = intel_get_screen_private(scrn);
 
@@ -1342,14 +1351,8 @@  i830_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
 		adaptor_priv->buf = NULL;
 	}
 
-	if (xvmc_passthrough(id)) {
+	if (xvmc_passthrough(id, adaptor_priv->rotation)) {
 		i830_free_video_buffers(adaptor_priv);
-		if (IS_I965G(intel)) {
-			adaptor_priv->buf =
-				drm_intel_bo_gem_create_from_name(intel->bufmgr,
-								  "xvmc surface",
-								  (uintptr_t)buf);
-		}
 	} else {
 		if (adaptor_priv->buf == NULL) {
 			adaptor_priv->buf = drm_intel_bo_alloc(intel->bufmgr,
@@ -1441,7 +1444,6 @@  i830_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
 		     INT32 x1, INT32 y1, INT32 x2, INT32 y2,
 		     int id, unsigned char *buf)
 {
-	intel_screen_private *intel = intel_get_screen_private(scrn);
 	int srcPitch = 0, srcPitch2 = 0;
 	int top, left, npixels, nlines, size;
 
@@ -1455,34 +1457,23 @@  i830_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
 	i830_dst_pitch_and_size(scrn, adaptor_priv, width, height, dstPitch,
 				dstPitch2, &size, id);
 
-	if (!i830_setup_video_buffer(scrn, adaptor_priv, size, id, buf))
+	if (!i830_setup_video_buffer(scrn, adaptor_priv, size, id))
 		return FALSE;
 
 	/* fixup pointers */
-#ifdef INTEL_XVMC
-	if (id == FOURCC_XVMC && IS_I915(intel)) {
-		adaptor_priv->YBufOffset = (uint32_t) ((uintptr_t) buf);
-		adaptor_priv->VBufOffset = adaptor_priv->YBufOffset + (*dstPitch2 * height);
+	adaptor_priv->YBufOffset = 0;
+
+	if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
 		adaptor_priv->UBufOffset =
-		    adaptor_priv->VBufOffset + (*dstPitch * height / 2);
+		    adaptor_priv->YBufOffset + (*dstPitch * 2 * width);
+		adaptor_priv->VBufOffset =
+		    adaptor_priv->UBufOffset + (*dstPitch * width / 2);
 	} else {
-#endif
-		adaptor_priv->YBufOffset = 0;
-
-		if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
-			adaptor_priv->UBufOffset =
-			    adaptor_priv->YBufOffset + (*dstPitch * 2 * width);
-			adaptor_priv->VBufOffset =
-			    adaptor_priv->UBufOffset + (*dstPitch * width / 2);
-		} else {
-			adaptor_priv->UBufOffset =
-			    adaptor_priv->YBufOffset + (*dstPitch * 2 * height);
-			adaptor_priv->VBufOffset =
-			    adaptor_priv->UBufOffset + (*dstPitch * height / 2);
-		}
-#ifdef INTEL_XVMC
+		adaptor_priv->UBufOffset =
+		    adaptor_priv->YBufOffset + (*dstPitch * 2 * height);
+		adaptor_priv->VBufOffset =
+		    adaptor_priv->UBufOffset + (*dstPitch * height / 2);
 	}
-#endif
 
 	/* copy data */
 	top = y1 >> 16;
@@ -1490,12 +1481,17 @@  i830_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
 	npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
 
 	if (is_planar_fourcc(id)) {
-		if (!xvmc_passthrough(id)) {
+		if (!xvmc_passthrough(id, adaptor_priv->rotation)) {
 			top &= ~1;
 			nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
 			I830CopyPlanarData(adaptor_priv, buf, srcPitch, srcPitch2,
 					   *dstPitch, height, top, left, nlines,
 					   npixels, id);
+		} else {
+			/* XVMC zero-copy passthrough. No memory leak here
+			 * because adaptor_priv->buf is freed in this case in
+			 * i830_setup_video_buffer */
+			adaptor_priv->buf = adaptor_priv->xvmc_passthrough_buf;
 		}
 	} else {
 		nlines = ((y2 + 0xffff) >> 16) - top;
@@ -1557,6 +1553,14 @@  I830PutImage(ScrnInfoPtr scrn,
 			drw_h = src_h / 7;
 	}
 
+#ifdef INTEL_XVMC
+	if (id == FOURCC_XVMC)
+		adaptor_priv->xvmc_passthrough_buf = (drm_intel_bo *) buf;
+	else
+#else
+		adaptor_priv->xvmc_passthrough_buf = NULL;
+#endif
+
 	/* Clip */
 	x1 = src_x;
 	x2 = src_x + src_w;
diff --git a/src/i830_video.h b/src/i830_video.h
index a2beae0..7e0da50 100644
--- a/src/i830_video.h
+++ b/src/i830_video.h
@@ -52,6 +52,7 @@  typedef struct {
 	Time freeTime;
 	/** YUV data buffers */
 	drm_intel_bo *buf;
+	drm_intel_bo *xvmc_passthrough_buf;
 
 	Bool textured;
 	Rotation rotation;	/* should remove intel->rotation later */
diff --git a/src/i915_hwmc.c b/src/i915_hwmc.c
index 8be52f2..ed772b6 100644
--- a/src/i915_hwmc.c
+++ b/src/i915_hwmc.c
@@ -515,7 +515,7 @@  static int i915_xvmc_create_context(ScrnInfoPtr scrn, XvMCContextPtr pContext,
 	contextRec->corrdata.size = ctxpriv->mcCorrdata->size;
 	contextRec->deviceID = DEVICE_ID(intel->PciInfo);
 
-	/* XXX: KMS */
+	/* XXX: KMS NEED_PHYSICAL_ADDR */
 #if 0
 	if (IS_I915G(intel) || IS_I915GM(intel)) {
 		contextRec->sis.bus_addr =
@@ -814,10 +814,13 @@  static int i915_xvmc_put_image(ScrnInfoPtr scrn,
 				return 1;
 			}
 
-			/* use char *buf to hold our surface offset...hacky! */
+			/* Ugly Hack (tm): Abuse buf to hold the drm_intel_bo
+			 * pointer. As long as the minimum Xv buffer required
+			 * is bigger than struct drm_intel_bo, this cannot be
+			 * exploited by userspace to crash X. */
 			buf =
 			    (unsigned char *)pXvMC->sfprivs[xvmc_cmd->srfNo]->
-			    surface->offset;
+			    surface->bo;
 			break;
 		default:
 			return 0;
diff --git a/src/i965_hwmc.c b/src/i965_hwmc.c
index 3fe4f41..f2e6b7e 100644
--- a/src/i965_hwmc.c
+++ b/src/i965_hwmc.c
@@ -158,11 +158,19 @@  static int put_image(ScrnInfoPtr scrn,
 		     short height, Bool sync, RegionPtr clipBoxes, pointer data,
 		     DrawablePtr drawable)
 {
+	intel_screen_private *intel = intel_get_screen_private(scrn);
 	struct intel_xvmc_command *cmd = (struct intel_xvmc_command *)buf;
+	drm_intel_bo *bo;
 
 	if (id == FOURCC_XVMC) {
-		/* Pass the GEM object name through the pointer arg. */
-		buf = (void *)(uintptr_t)cmd->handle;
+		bo = intel_bo_gem_create_from_name(intel->bufmgr, "surface",
+				cmd->handle);
+
+		/* Ugly Hack (tm): Abuse buf to hold the drm_intel_bo pointer.
+		 * As long as the minimum Xv buffer required is bigger than
+		 * struct drm_intel_bo, this cannot be exploited by userspace to
+		 * crash X. */
+		buf = (unsigned char *) bo;
 	}
 
 	savedXvPutImage(scrn, src_x, src_y, drw_x, drw_y, src_w, src_h,