From: Rob Clark <r...@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

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to