[PATCH xserver] add dri2video

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


From: Rob Clark <rob at ti.com>

TODO:
 + implement OSD support.. core should register damage and automatically
   re-call ScheduleSwapVid..
 + automatically re-call ScheduleSwapVid on dri2 drawable resize...
---
 hw/xfree86/dri2/dri2.c    |  364 +++++++++++++++++++++++++++++++++++++--------
 hw/xfree86/dri2/dri2.h    |  127 ++++++++++++++++-
 hw/xfree86/dri2/dri2ext.c |  214 +++++++++++++++++++++++++-
 3 files changed, 631 insertions(+), 74 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index a97508d..89a7fed 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -91,6 +91,8 @@ typedef struct _DRI2Screen {
     int				 refcnt;
     unsigned int		 numDrivers;
     const char			**driverNames;
+    unsigned int		 numFormats;
+    unsigned int		*formats;
     const char			*deviceName;
     int				 fd;
     unsigned int		 lastSequence;
@@ -104,12 +106,27 @@ typedef struct _DRI2Screen {
     DRI2AuthMagicProcPtr	 AuthMagic;
     DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
     DRI2SwapLimitValidateProcPtr SwapLimitValidate;
+    DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames;
+    DRI2CreateBufferVidProcPtr	 CreateBufferVid;
+    DRI2ScheduleSwapVidProcPtr	 ScheduleSwapVid;
+    DRI2SetAttributeProcPtr	 SetAttribute;
+    DRI2GetAttributeProcPtr	 GetAttribute;
 
     HandleExposuresProcPtr       HandleExposures;
 
     ConfigNotifyProcPtr		 ConfigNotify;
 } DRI2ScreenRec;
 
+static Bool
+supports_video(DRI2ScreenPtr ds)
+{
+    /* it would be easier if we had a way to track the driverType in the
+     * DRI2DrawablePtr.. but the DRI2DrawablePtr isn't created at the
+     * time of DRI2Connect()..
+     */
+    return ds && ds->numFormats && ds->CreateBufferVid && ds->ScheduleSwapVid;
+}
+
 static DRI2ScreenPtr
 DRI2GetScreen(ScreenPtr pScreen)
 {
@@ -296,15 +313,26 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
     return Success;
 }
 
+static void destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr *buffers, int count)
+{
+    if (buffers != NULL) {
+	DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+	int i;
+	for (i = 0; i < count; i++)
+	    if (buffers[i])
+		(*ds->DestroyBuffer)(pDraw, buffers[i]);
+
+	free(buffers);
+    }
+}
+
 static int DRI2DrawableGone(pointer p, XID id)
 {
     DRI2DrawablePtr pPriv = p;
-    DRI2ScreenPtr   ds = pPriv->dri2_screen;
     DRI2DrawableRefPtr ref, next;
     WindowPtr pWin;
     PixmapPtr pPixmap;
     DrawablePtr pDraw;
-    int i;
 
     list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
 	if (ref->dri2_id == id) {
@@ -336,12 +364,7 @@ static int DRI2DrawableGone(pointer p, XID id)
 	dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
     }
 
-    if (pPriv->buffers != NULL) {
-	for (i = 0; i < pPriv->bufferCount; i++)
-	    (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
-
-	free(pPriv->buffers);
-    }
+    destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
 
     free(pPriv);
 
@@ -349,7 +372,7 @@ static int DRI2DrawableGone(pointer p, XID id)
 }
 
 static int
-find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
+find_attachment(DRI2DrawablePtr pPriv, unsigned attachment, DRI2BufferPtr *buf)
 {
     int i;
 
@@ -360,6 +383,8 @@ find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
     for (i = 0; i < pPriv->bufferCount; i++) {
 	if ((pPriv->buffers[i] != NULL)
 	    && (pPriv->buffers[i]->attachment == attachment)) {
+	    if (buf)
+		*buf = pPriv->buffers[i];
 	    return i;
 	}
     }
@@ -368,12 +393,24 @@ find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
 }
 
 static Bool
+valid_format(DRI2ScreenPtr ds, unsigned int format)
+{
+    int i;
+    for (i = 0; i < ds->numFormats; i++) {
+	if (format == ds->formats[i]) {
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+static Bool
 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
 			 DRI2DrawablePtr pPriv,
 			 unsigned int attachment, unsigned int format,
 			 int dimensions_match, DRI2BufferPtr *buffer)
 {
-    int old_buf = find_attachment(pPriv, attachment);
+    int old_buf = find_attachment(pPriv, attachment, NULL);
 
     if ((old_buf < 0)
 	|| !dimensions_match
@@ -397,18 +434,7 @@ static void
 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
 			     DRI2BufferPtr *buffers, int out_count, int *width, int *height)
 {
-    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
-    int i;
-
-    if (pPriv->buffers != NULL) {
-	for (i = 0; i < pPriv->bufferCount; i++) {
-	    if (pPriv->buffers[i] != NULL) {
-		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
-	    }
-	}
-
-	free(pPriv->buffers);
-    }
+    destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
 
     pPriv->buffers = buffers;
     pPriv->bufferCount = out_count;
@@ -453,6 +479,15 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
 	const unsigned attachment = *(attachments++);
 	const unsigned format = (has_format) ? *(attachments++) : 0;
 
+	/* note: don't require a valid format for old drivers which don't
+	 * register their supported formats..
+	 */
+	if (has_format && (ds->numFormats > 0) && !valid_format(ds, format)) {
+	    xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
+		    "[DRI2] %s: bad format: %d\n", __func__, format);
+	    goto err_out;
+	}
+
 	if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
 				     format, dimensions_match,
 				     &buffers[i]))
@@ -542,19 +577,11 @@ err_out:
 
     *out_count = 0;
 
-    if (buffers) {
-	for (i = 0; i < count; i++) {
-	    if (buffers[i] != NULL)
-		(*ds->DestroyBuffer)(pDraw, buffers[i]);
-	}
-
-	free(buffers);
-	buffers = NULL;
-    }
+    destroy_buffers(pDraw, buffers, count);
 
-    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height);
+    update_dri2_drawable_buffers(pPriv, pDraw, NULL, *out_count, width, height);
 
-    return buffers;
+    return NULL;
 }
 
 DRI2BufferPtr *
@@ -573,6 +600,95 @@ DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
 			  out_count, TRUE);
 }
 
+DRI2BufferPtr *
+DRI2GetBuffersVid(DrawablePtr pDraw, int width, int height,
+	unsigned int *attachments, int count, int *out_count)
+{
+    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
+    DRI2BufferPtr  *buffers;
+    int i, n = 0;
+
+    if (!pPriv || !supports_video(ds)) {
+	*out_count = 0;
+	return NULL;
+    }
+
+    buffers = calloc(count, sizeof(buffers[0]));
+    if (!buffers)
+	goto err_out;
+
+    for (i = 0; i < count; i++) {
+	DRI2BufferPtr buf;
+	const unsigned attachment = *(attachments++);
+	const unsigned format = *(attachments++);
+
+	/* grow array of stored buffers if needed: */
+	if (attachment >= pPriv->bufferCount) {
+	    int n = attachment + 1;
+	    DRI2BufferPtr *newBuffers = realloc(pPriv->buffers,
+		    sizeof(pPriv->buffers[0]) * n);
+	    if (!newBuffers) {
+		xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
+			"[DRI2] %s: allocation failed for buffer: %d\n",
+			__func__, attachment);
+		goto err_out;
+	    }
+	    pPriv->buffers = newBuffers;
+	    memset(&pPriv->buffers[pPriv->bufferCount], 0,
+		    (n - pPriv->bufferCount) * sizeof(pPriv->buffers[0]));
+	    pPriv->bufferCount = n;
+	}
+
+	/* destroy any previous buffer at this attachment slot */
+	if (pPriv->buffers[attachment]) {
+	    (*ds->DestroyBuffer)(pDraw, pPriv->buffers[attachment]);
+	    pPriv->buffers[attachment] = NULL;
+	}
+
+	if ((width == 0) && (height == 0)) {
+	    /* client just wanted us to delete the buffer */
+	    continue;
+	}
+
+	if (!valid_format(ds, format)) {
+	    xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
+		    "[DRI2] %s: bad format: %d\n", __func__, format);
+	    goto err_out;
+	}
+
+	if (attachment == DRI2BufferFrontLeft) {
+	    buf = (*ds->CreateBuffer)(pDraw, attachment, format);
+	    /* note: don't expose front buffer to client */
+	} else {
+	    buf = (*ds->CreateBufferVid)(pDraw, attachment, format, width, height);
+	    buffers[n++] = buf;
+	}
+
+	if (! buf) {
+	    goto err_out;
+	}
+
+	pPriv->buffers[attachment] = buf;
+    }
+
+    *out_count = n;
+
+    return buffers;
+
+err_out:
+
+    *out_count = 0;
+
+    for (i = 0; i < n; i++)
+	if (buffers[i])
+	    pPriv->buffers[buffers[i]->attachment] = NULL;
+
+    destroy_buffers(pDraw, buffers, n);
+
+    return NULL;
+}
+
 static void
 DRI2InvalidateDrawable(DrawablePtr pDraw)
 {
@@ -645,22 +761,14 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
 {
     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
     DRI2DrawablePtr pPriv;
-    DRI2BufferPtr   pDestBuffer, pSrcBuffer;
-    int		    i;
+    DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL;
 
     pPriv = DRI2GetDrawable(pDraw);
     if (pPriv == NULL)
 	return BadDrawable;
 
-    pDestBuffer = NULL;
-    pSrcBuffer = NULL;
-    for (i = 0; i < pPriv->bufferCount; i++)
-    {
-	if (pPriv->buffers[i]->attachment == dest)
-	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
-	if (pPriv->buffers[i]->attachment == src)
-	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
-    }
+    find_attachment(pPriv, dest, &pDestBuffer);
+    find_attachment(pPriv, src, &pSrcBuffer);
     if (pSrcBuffer == NULL || pDestBuffer == NULL)
 	return BadValue;
 
@@ -827,31 +935,28 @@ DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
     return FALSE;
 }
 
-int
-DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
-		CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
-		DRI2SwapEventPtr func, void *data)
+static int
+swap_buffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
+	     CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
+	     DRI2SwapEventPtr func, void *data,
+	     Bool vid, unsigned int source, BoxPtr b)
 {
     ScreenPtr       pScreen = pDraw->pScreen;
     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
-    DRI2DrawablePtr pPriv;
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
     DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL;
-    int             ret, i;
+    int             ret;
     CARD64          ust, current_msc;
 
-    pPriv = DRI2GetDrawable(pDraw);
-    if (pPriv == NULL) {
+    if ((pPriv == NULL) || (vid && !supports_video(ds))) {
         xf86DrvMsg(pScreen->myNum, X_ERROR,
 		   "[DRI2] %s: bad drawable\n", __func__);
 	return BadDrawable;
     }
 
-    for (i = 0; i < pPriv->bufferCount; i++) {
-	if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
-	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
-	if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
-	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
-    }
+    find_attachment(pPriv, DRI2BufferFrontLeft, &pDestBuffer);
+    find_attachment(pPriv, source, &pSrcBuffer);
+
     if (pSrcBuffer == NULL || pDestBuffer == NULL) {
         xf86DrvMsg(pScreen->myNum, X_ERROR,
 		   "[DRI2] %s: drawable has no back or front?\n", __func__);
@@ -859,7 +964,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     }
 
     /* Old DDX or no swap interval, just blit */
-    if (!ds->ScheduleSwap || !pPriv->swap_interval) {
+    if ((!ds->ScheduleSwap || !pPriv->swap_interval) && !vid) {
 	BoxRec box;
 	RegionRec region;
 
@@ -895,7 +1000,6 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
 
 	    if (current_msc < pPriv->last_swap_target)
 		pPriv->last_swap_target = current_msc;
-
 	}
 
 	/*
@@ -911,8 +1015,14 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     }
 
     pPriv->swapsPending++;
-    ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
-			      swap_target, divisor, remainder, func, data);
+    if (vid) {
+	DrawablePtr osd = NULL;  // TODO
+	ret = (*ds->ScheduleSwapVid)(client, pDraw, pDestBuffer, pSrcBuffer,
+		b, osd, swap_target, divisor, remainder, func, data);
+    } else {
+	ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
+		swap_target, divisor, remainder, func, data);
+    }
     if (!ret) {
 	pPriv->swapsPending--; /* didn't schedule */
         xf86DrvMsg(pScreen->myNum, X_ERROR,
@@ -927,11 +1037,31 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
      */
     *swap_target = pPriv->swap_count + pPriv->swapsPending;
 
-    DRI2InvalidateDrawable(pDraw);
+    if (!vid) {
+	DRI2InvalidateDrawable(pDraw);
+    }
 
     return Success;
 }
 
+int
+DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
+		CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
+		DRI2SwapEventPtr func, void *data)
+{
+    return swap_buffers(client, pDraw, target_msc, divisor, remainder,
+	    swap_target, func, data, FALSE, DRI2BufferBackLeft, NULL);
+}
+
+int
+DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
+		CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
+		unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data)
+{
+    return swap_buffers(client, pDraw, target_msc, divisor, remainder,
+	    swap_target, func, data, TRUE, source, b);
+}
+
 void
 DRI2SwapInterval(DrawablePtr pDrawable, int interval)
 {
@@ -1049,6 +1179,77 @@ DRI2HasSwapControl(ScreenPtr pScreen)
     return ds->ScheduleSwap && ds->GetMSC;
 }
 
+#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+/* length in multiple of CARD32's, passed in value should be copied by
+ * receiver
+ */
+int
+DRI2SetAttribute(DrawablePtr pDraw, Atom attribute, int len, const CARD32 *val)
+{
+    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+    int ret = BadMatch;
+
+    if (!supports_video(ds)) {
+	return BadDrawable;
+    }
+
+    if (attribute == ATOM("XV_OSD")) {
+    } else if (ds->SetAttribute) {
+	ret = (*ds->SetAttribute)(pDraw, attribute, len, val);
+    }
+
+    return ret;
+}
+
+/* length in multiple of CARD32's, returned val should *not* be free'd
+ * (unlike similar function on client side) to avoid temporary allocation
+ * and extra copy.
+ */
+int
+DRI2GetAttribute(DrawablePtr pDraw, Atom attribute, int *len, const CARD32 **val)
+{
+    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+    int ret = BadMatch;
+
+    if (!supports_video(ds)) {
+	return BadDrawable;
+    }
+
+    if (attribute == ATOM("XV_OSD")) {
+    } else if (ds->GetAttribute) {
+	ret = (*ds->GetAttribute)(pDraw, attribute, len, val);
+    }
+
+    return ret;
+}
+
+int
+DRI2GetFormats(ScreenPtr pScreen, unsigned int *nformats, unsigned int **formats)
+{
+    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
+
+    if (! supports_video(ds)) {
+	return BadDrawable;
+    }
+
+    *nformats = ds->numFormats;
+    *formats  = ds->formats;
+
+    return Success;
+}
+
+unsigned int
+DRI2GetExtraBufferNames(DrawablePtr pDraw, DRI2BufferPtr buf,
+	unsigned int **names, unsigned int **pitches)
+{
+    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+    if (ds->GetExtraBufferNames) {
+	return (*ds->GetExtraBufferNames)(pDraw, buf, names, pitches);
+    }
+    return 0;
+}
+
 Bool
 DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
 	    const char **driverName, const char **deviceName)
@@ -1116,9 +1317,10 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
     const char* driverTypeNames[] = {
 	"DRI", /* DRI2DriverDRI */
 	"VDPAU", /* DRI2DriverVDPAU */
+	"XV", /* DRI2DriverXV */
     };
     unsigned int i;
-    CARD8 cur_minor;
+    CARD8 cur_minor = 1;
 
     if (info->version < 3)
 	return FALSE;
@@ -1156,8 +1358,6 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 	ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
 	ds->GetMSC = info->GetMSC;
 	cur_minor = 3;
-    } else {
-	cur_minor = 1;
     }
 
     if (info->version >= 5) {
@@ -1169,6 +1369,34 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 	ds->SwapLimitValidate = info->SwapLimitValidate;
     }
 
+    if (info->version >= 7) {
+	if ((info->numDrivers > DRI2DriverXV) &&
+		info->driverNames[DRI2DriverXV]) {
+	    /* if driver claims to support DRI2DriverXV, then ensure
+	     * it provides the required fxn ptrs:
+	     */
+	    if (!info->CreateBufferVid || !info->ScheduleSwapVid) {
+		xf86DrvMsg(pScreen->myNum, X_WARNING,
+			"[DRI2] DRI2DriverXV must implement "
+			"CreateBuffersVid and ScheduleSwapVid.\n");
+		goto err_out;
+	    }
+	}
+	ds->numFormats = info->numFormats;
+	ds->formats = malloc(info->numFormats * sizeof(*ds->formats));
+	if (!ds->formats)
+	    goto err_out;
+	memcpy(ds->formats, info->formats,
+		info->numFormats * sizeof(*ds->formats));
+	ds->GetExtraBufferNames = info->GetExtraBufferNames;
+	ds->CreateBufferVid = info->CreateBufferVid;
+	ds->ScheduleSwapVid = info->ScheduleSwapVid;
+	ds->SetAttribute = info->SetAttribute;
+	ds->GetAttribute = info->GetAttribute;
+
+	cur_minor = 4;
+    }
+
     /*
      * if the driver doesn't provide an AuthMagic function or the info struct
      * version is too low, it relies on the old method (using libdrm) or fail
@@ -1218,6 +1446,10 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 err_out:
     xf86DrvMsg(pScreen->myNum, X_WARNING,
             "[DRI2] Initialization failed for info version %d.\n", info->version);
+    if (ds) {
+	free(ds->formats);
+	free(ds->driverNames);
+    }
     free(ds);
     return FALSE;
 }
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index 9c93209..984943b 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -104,9 +104,60 @@ typedef int		(*DRI2ScheduleSwapProcPtr)(ClientPtr client,
 						   CARD64 remainder,
 						   DRI2SwapEventPtr func,
 						   void *data);
+
+/**
+ * Schedule a video buffer swap
+ *
+ * Drivers should queue an event for the frame count that satisfies the
+ * parameters passed in.  If the event is in the future (i.e. the conditions
+ * aren't currently satisfied), the server may block the client at the next
+ * GLX request using DRI2WaitSwap. When the event arrives, drivers should call
+ * \c DRI2SwapComplete, which will handle waking the client and returning
+ * the appropriate data.
+ *
+ * The DDX is responsible for doing an overlay buffer flip/exchange, or
+ * scaling/colorconvert blit when the corresponding event arrives.
+ *
+ * If the target drawable is resized/damaged, or the osd pixmap is changed/
+ * damaged, ScheduleSwapVid can be re-invoked by the core with the same
+ * source buffer to repair the dri2 video drawable.
+ * XXX TODO this part isn't implemented in core yet..
+ *
+ * \param client client pointer (used for block/unblock)
+ * \param pDraw drawable whose count we want
+ * \param pDestBuffer current front buffer
+ * \param pSrcBuffer current back buffer
+ * \param b the crop box
+ * \param osd the on-screen-display overlay pixmap, should be an ARGB pixmap
+ *   that is blended on top of the video as part of swap.  Multiple layers
+ *   to blend over the video should be flattened into a single layer by the
+ *   client
+ * \param target_msc frame count to wait for
+ * \param divisor divisor for condition equation
+ * \param remainder remainder for division equation
+ * \param func function to call when the swap completes
+ * \param data data for the callback \p func.
+ */
+typedef int		(*DRI2ScheduleSwapVidProcPtr)(ClientPtr client,
+						   DrawablePtr pDraw,
+						   DRI2BufferPtr pDestBuffer,
+						   DRI2BufferPtr pSrcBuffer,
+						   BoxPtr b,
+						   DrawablePtr osd,
+						   CARD64 *target_msc,
+						   CARD64 divisor,
+						   CARD64 remainder,
+						   DRI2SwapEventPtr func,
+						   void *data);
+
 typedef DRI2BufferPtr	(*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
 						   unsigned int attachment,
 						   unsigned int format);
+typedef DRI2BufferPtr	(*DRI2CreateBufferVidProcPtr)(DrawablePtr pDraw,
+						   unsigned int attachment,
+						   unsigned int format,
+						   unsigned int width,
+						   unsigned int height);
 typedef void		(*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
 						    DRI2BufferPtr buffer);
 /**
@@ -181,10 +232,46 @@ typedef void		(*DRI2InvalidateProcPtr)(DrawablePtr pDraw,
 typedef Bool		(*DRI2SwapLimitValidateProcPtr)(DrawablePtr pDraw,
 							int swap_limit);
 
+
+/**
+ * An ugly approach to avoid changing DRI2BufferPtr and cause ABI breakage
+ * between driver and xserver.  This only needs to be implemented by drivers
+ * supporting planar formats with one buffer per plane.
+ *
+ * This might be a good argument for having drivers in-tree ;-)
+ *
+ * \param pDraw drawable that the buffer belongs to
+ * \param buf the DRI2 buffer
+ * \param names array of buffer names
+ * \param pitches array of buffer pitches
+ * \return the number of additional buffers, ie. for I420 tri-planar buffer,
+ * if represented as multiple buffer names, the Y buffer name would be in
+ * buf->name, this function would return 2, and return the U and V buffer
+ * names by reference.
+ */
+typedef unsigned int	(*DRI2GetExtraBufferNamesProcPtr)(DrawablePtr pDraw,
+	DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches);
+
+/**
+ * Length in multiple of CARD32's, passed in value should be copied by
+ * receiver
+ */
+typedef int (*DRI2SetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute,
+	int len, const CARD32 *val);
+
+/**
+ * Length in multiple of CARD32's, returned val should *not* be free'd
+ * (unlike similar function on client side) to avoid temporary allocation
+ * and extra copy.
+ */
+typedef int (*DRI2GetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute,
+	int *len, const CARD32 **val);
+
+
 /**
  * Version of the DRI2InfoRec structure defined in this header
  */
-#define DRI2INFOREC_VERSION 6
+#define DRI2INFOREC_VERSION 7
 
 typedef struct {
     unsigned int version;	/**< Version of this struct */
@@ -217,6 +304,17 @@ typedef struct {
 
     DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
     DRI2SwapLimitValidateProcPtr SwapLimitValidate;
+
+    /* added in version 7 */
+
+    unsigned int numFormats;
+    const unsigned int *formats;
+    DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames;
+    DRI2CreateBufferVidProcPtr	CreateBufferVid;
+    DRI2ScheduleSwapVidProcPtr	ScheduleSwapVid;
+    DRI2SetAttributeProcPtr	SetAttribute;
+    DRI2GetAttributeProcPtr	GetAttribute;
+
 }  DRI2InfoRec, *DRI2InfoPtr;
 
 extern _X_EXPORT int DRI2EventBase;
@@ -278,12 +376,21 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
 	int *width, int *height, unsigned int *attachments, int count,
 	int *out_count);
 
+extern _X_EXPORT DRI2BufferPtr * DRI2GetBuffersVid(DrawablePtr pDraw,
+	int width, int height, unsigned int *attachments, int count,
+	int *out_count);
+
 extern _X_EXPORT void DRI2SwapInterval(DrawablePtr pDrawable, int interval);
 extern _X_EXPORT Bool DRI2SwapLimit(DrawablePtr pDraw, int swap_limit);
 extern _X_EXPORT int DRI2SwapBuffers(ClientPtr client, DrawablePtr pDrawable,
 				     CARD64 target_msc, CARD64 divisor,
 				     CARD64 remainder, CARD64 *swap_target,
 				     DRI2SwapEventPtr func, void *data);
+
+extern _X_EXPORT int DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw,
+	CARD64 target_msc, CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
+	unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data);
+
 extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable);
 
 extern _X_EXPORT int DRI2GetMSC(DrawablePtr pDrawable, CARD64 *ust,
@@ -313,4 +420,22 @@ extern _X_EXPORT void DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw,
 					  int frame, unsigned int tv_sec,
 					  unsigned int tv_usec);
 
+extern _X_EXPORT int DRI2SetAttribute(DrawablePtr pDraw, Atom attribute,
+	int len, const CARD32 *val);
+extern _X_EXPORT int DRI2GetAttribute(DrawablePtr pDraw, Atom attribute,
+	int *len, const CARD32 **val);
+extern _X_EXPORT int DRI2GetFormats(ScreenPtr pScreen,
+	unsigned int *nformats, unsigned int **formats);
+
+extern _X_EXPORT unsigned int DRI2GetExtraBufferNames(DrawablePtr pDraw,
+	DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches);
+
+
+/* some utility macros.. maybe could go elsewhere? */
+#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])
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(_a)   (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
 #endif
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index 934abf6..e0250b9 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -76,6 +76,7 @@ ProcDRI2QueryVersion(ClientPtr client)
 	swaps(&stuff->length);
 
     REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
+
     rep.type = X_Reply;
     rep.length = 0;
     rep.sequenceNumber = client->sequence;
@@ -204,12 +205,13 @@ ProcDRI2DestroyDrawable(ClientPtr client)
 
 
 static int
-send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
+send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, int vid,
 		   DRI2BufferPtr *buffers, int count, int width, int height)
 {
     xDRI2GetBuffersReply rep;
-    int skip = 0;
-    int i;
+    int skip = 0, extra = 0;
+    unsigned int *names, *pitches;
+    int i, j;
 
     if (buffers == NULL)
 	    return BadAlloc;
@@ -225,8 +227,24 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
 	}
     }
 
+    if (vid) {
+	extra = 4 * (count - skip);
+
+	for (i = 0; i < count; i++) {
+	    /* Do not send the real front buffer of a window to the client.
+	     */
+	    if ((pDrawable->type == DRAWABLE_WINDOW)
+		    && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
+		continue;
+	    }
+
+	    extra += 8 * DRI2GetExtraBufferNames(pDrawable, buffers[i],
+		    &names, &pitches);
+	}
+    }
+
     rep.type = X_Reply;
-    rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
+    rep.length = ((count - skip) * sizeof(xDRI2Buffer) + extra) / 4;
     rep.sequenceNumber = client->sequence;
     rep.width = width;
     rep.height = height;
@@ -249,6 +267,17 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
 	buffer.cpp = buffers[i]->cpp;
 	buffer.flags = buffers[i]->flags;
 	WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
+
+	if (vid) {
+	    CARD32 n = DRI2GetExtraBufferNames(pDrawable, buffers[i],
+		    &names, &pitches);
+	    WriteToClient(client, sizeof(n), &n);
+	    for (j = 0; j < n; j++) {
+		CARD32 name = names[j], pitch = pitches[j];
+		WriteToClient(client, sizeof(name), &name);
+		WriteToClient(client, sizeof(pitch), &pitch);
+	    }
+	}
     }
     return Success;
 }
@@ -276,8 +305,8 @@ ProcDRI2GetBuffers(ClientPtr client)
 			     attachments, stuff->count, &count);
 
 
-    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
-
+    return send_buffers_reply(client, pDrawable, FALSE,
+	    buffers, count, width, height);
 }
 
 static int
@@ -301,7 +330,40 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
 				       attachments, stuff->count, &count);
 
-    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
+    return send_buffers_reply(client, pDrawable, FALSE,
+	    buffers, count, width, height);
+}
+
+static int
+ProcDRI2GetBuffersVid(ClientPtr client)
+{
+    REQUEST(xDRI2GetBuffersVidReq);
+    DrawablePtr pDrawable;
+    DRI2BufferPtr *buffers;
+    int status, count;
+    unsigned int *attachments;
+
+    REQUEST_FIXED_SIZE(xDRI2GetBuffersVidReq, stuff->count * (2 * 4));
+    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
+		       &pDrawable, &status))
+	return status;
+
+    if (DRI2ThrottleClient(client, pDrawable))
+	return Success;
+
+    attachments = (unsigned int *) &stuff[1];
+    buffers = DRI2GetBuffersVid(pDrawable, stuff->width, stuff->height,
+				attachments, stuff->count, &count);
+
+    status = send_buffers_reply(client, pDrawable, TRUE, buffers, count, 0, 0);
+
+    /* note, unlike other DRI2GetBuffers variants, we allow requesting/
+     * returning just a subset of buffers.. so array that is returned is
+     * not the one held in pPriv, so must be free'd
+     */
+    free(buffers);
+
+    return status;
 }
 
 static int
@@ -414,6 +476,53 @@ ProcDRI2SwapBuffers(ClientPtr client)
     return Success;
 }
 
+static int
+ProcDRI2SwapBuffersVid(ClientPtr client)
+{
+    REQUEST(xDRI2SwapBuffersVidReq);
+    xDRI2SwapBuffersReply rep;
+    DrawablePtr pDrawable;
+    CARD64 target_msc, divisor, remainder, swap_target;
+    BoxRec b;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI2SwapBuffersVidReq);
+
+    if (!validDrawable(client, stuff->drawable,
+		       DixReadAccess | DixWriteAccess, &pDrawable, &status))
+	return status;
+
+    /*
+     * Ensures an out of control client can't exhaust our swap queue, and
+     * also orders swaps.
+     */
+    if (DRI2ThrottleClient(client, pDrawable))
+	return Success;
+
+    target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
+    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
+    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
+
+    b.x1 = stuff->x1;
+    b.y1 = stuff->y1;
+    b.x2 = stuff->x2;
+    b.y2 = stuff->y2;
+
+    status = DRI2SwapBuffersVid(client, pDrawable, target_msc, divisor, remainder,
+	    &swap_target, stuff->source, &b, DRI2SwapEvent, pDrawable);
+    if (status != Success)
+	return BadDrawable;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    load_swap_reply(&rep, swap_target);
+
+    WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
+
+    return Success;
+}
+
 static void
 load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
 {
@@ -537,6 +646,87 @@ ProcDRI2WaitSBC(ClientPtr client)
 }
 
 static int
+ProcDRI2SetAttribute(ClientPtr client)
+{
+    REQUEST(xDRI2SetAttributeReq);
+    DrawablePtr pDrawable;
+    int status;
+    int len = (stuff->length * 4 - sizeof(xDRI2SetAttributeReq)) / 4;
+
+    REQUEST_FIXED_SIZE(xDRI2SetAttributeReq, len * 4);
+
+    if (!validDrawable(client, stuff->drawable,
+	    DixReadAccess | DixWriteAccess, &pDrawable, &status))
+	return status;
+
+    status = DRI2SetAttribute(pDrawable, stuff->attribute, len,
+	    (const CARD32 *)&stuff[1]);
+    if (status != Success)
+	return status;
+
+    return Success;
+}
+
+static int
+ProcDRI2GetAttribute(ClientPtr client)
+{
+    REQUEST(xDRI2GetAttributeReq);
+    xDRI2GetAttributeReply rep;
+    DrawablePtr pDrawable;
+    const CARD32 *val;
+    int status, len;
+
+    REQUEST_SIZE_MATCH(xDRI2GetAttributeReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
+	    &status))
+	return status;
+
+    status = DRI2GetAttribute(pDrawable, stuff->attribute, &len, &val);
+    if (status != Success)
+	return status;
+
+    rep.type = X_Reply;
+    rep.length = len;
+    rep.sequenceNumber = client->sequence;
+    WriteToClient(client, sizeof(xDRI2GetAttributeReply), &rep);
+    WriteToClient(client, len * 4, val);
+
+    return Success;
+}
+
+static int
+ProcDRI2GetFormats(ClientPtr client)
+{
+    REQUEST(xDRI2GetFormatsReq);
+    xDRI2GetFormatsReply rep;
+    DrawablePtr pDrawable;
+    unsigned int i, nformats, *formats;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI2GetFormatsReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
+	    &status))
+	return status;
+
+    status = DRI2GetFormats(pDrawable->pScreen, &nformats, &formats);
+    if (status != Success)
+	return status;
+
+    rep.type = X_Reply;
+    rep.length = nformats * sizeof(*formats) / 4;
+    rep.sequenceNumber = client->sequence;
+    WriteToClient(client, sizeof(xDRI2GetFormatsReply), &rep);
+
+    for (i = 0; i < nformats; i++) {
+	WriteToClient(client, sizeof(formats[i]), &formats[i]);
+    }
+
+    return Success;
+}
+
+static int
 ProcDRI2Dispatch (ClientPtr client)
 {
     REQUEST(xReq);
@@ -574,6 +764,16 @@ ProcDRI2Dispatch (ClientPtr client)
 	return ProcDRI2WaitSBC(client);
     case X_DRI2SwapInterval:
 	return ProcDRI2SwapInterval(client);
+    case X_DRI2GetBuffersVid:
+	return ProcDRI2GetBuffersVid(client);
+    case X_DRI2SwapBuffersVid:
+	return ProcDRI2SwapBuffersVid(client);
+    case X_DRI2SetAttribute:
+	return ProcDRI2SetAttribute(client);
+    case X_DRI2GetAttribute:
+	return ProcDRI2GetAttribute(client);
+    case X_DRI2GetFormats:
+	return ProcDRI2GetFormats(client);
     default:
 	return BadRequest;
     }
-- 
1.7.5.4



More information about the xorg-devel mailing list