@@ -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;
@@ -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;
@@ -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 */
@@ -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;
@@ -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,