The old DRI2 buffer allocation API wasn't great, but there's no reason to
make the server stop working with those drivers. This patch has the
X server adapting to the API provided by the driver, using the new API where
available and falling back to the old API as necessary. A warning will be
placed in the log file when the old API is in use.

Signed-off-by: Keith Packard <[email protected]>
---
 hw/xfree86/dri2/dri2.c    |  254 ++++++++++++++++++++++++++++++++-------------
 hw/xfree86/dri2/dri2.h    |   31 ++++--
 hw/xfree86/dri2/dri2ext.c |    6 +-
 3 files changed, 208 insertions(+), 83 deletions(-)

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 385c5e8..3864e0d 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -53,7 +53,7 @@ typedef struct _DRI2Drawable {
     unsigned int        refCount;
     int                         width;
     int                         height;
-    DRI2BufferPtr      *buffers;
+    DRI2Buffer2Ptr     *buffers;
     int                         bufferCount;
     unsigned int        pendingSequence;
 } DRI2DrawableRec, *DRI2DrawablePtr;
@@ -63,6 +63,10 @@ typedef struct _DRI2Screen {
     const char                 *deviceName;
     int                                 fd;
     unsigned int                lastSequence;
+
+    DRI2CreateBuffersProcPtr    CreateBuffers;
+    DRI2DestroyBuffersProcPtr   DestroyBuffers;
+
     DRI2CreateBufferProcPtr     CreateBuffer;
     DRI2DestroyBufferProcPtr    DestroyBuffer;
     DRI2CopyRegionProcPtr       CopyRegion;
@@ -133,17 +137,17 @@ DRI2CreateDrawable(DrawablePtr pDraw)
 }
 
 static int
-find_attachment(DRI2BufferPtr *buffer_list, int count, unsigned attachment)
+find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
 {
     int i;
 
-    if (buffer_list == NULL) {
+    if (pPriv->buffers == NULL) {
        return -1;
     }
 
-    for (i = 0; i < count; i++) {
-       if ((buffer_list[i] != NULL)
-           && (buffer_list[i]->attachment == attachment)) {
+    for (i = 0; i < pPriv->bufferCount; i++) {
+       if ((pPriv->buffers[i] != NULL)
+           && (pPriv->buffers[i]->attachment == attachment)) {
            return i;
        }
     }
@@ -151,16 +155,16 @@ find_attachment(DRI2BufferPtr *buffer_list, int count, 
unsigned attachment)
     return -1;
 }
 
-static DRI2BufferPtr
+static DRI2Buffer2Ptr
 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
                         DRI2DrawablePtr pPriv,
                         unsigned int attachment, unsigned int format,
                         int dimensions_match)
 {
-    DRI2BufferPtr buffer;
+    DRI2Buffer2Ptr buffer;
     int old_buf;
 
-    old_buf = find_attachment(pPriv->buffers, pPriv->bufferCount, attachment);
+    old_buf = find_attachment(pPriv, attachment);
 
     if ((old_buf < 0)
        || !dimensions_match
@@ -174,14 +178,14 @@ allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr 
ds,
     return buffer;
 }
 
-static DRI2BufferPtr *
+static DRI2Buffer2Ptr *
 do_get_buffers(DrawablePtr pDraw, int *width, int *height,
               unsigned int *attachments, int count, int *out_count,
               int has_format)
 {
     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
-    DRI2BufferPtr  *buffers;
+    DRI2Buffer2Ptr  *buffers;
     int need_real_front = 0;
     int need_fake_front = 0;
     int have_fake_front = 0;
@@ -190,70 +194,157 @@ do_get_buffers(DrawablePtr pDraw, int *width, int 
*height,
        && (pDraw->height == pPriv->height);
     int i;
 
-
     buffers = xalloc((count + 1) * sizeof(buffers[0]));
 
-    for (i = 0; i < count; i++) {
-       const unsigned attachment = *(attachments++);
-       const unsigned format = (has_format) ? *(attachments++) : 0;
+    if (ds->CreateBuffer) {
+       /* Version 2 API with CreateBuffer */
+       for (i = 0; i < count; i++) {
+           const unsigned attachment = *(attachments++);
+           const unsigned format = (has_format) ? *(attachments++) : 0;
+
+           buffers[i] = allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
+                                                 format, dimensions_match);
+
+           /* If the drawable is a window and the front-buffer is requested,
+            * silently add the fake front-buffer to the list of requested
+            * attachments.  The counting logic in the loop accounts for the 
case
+            * where the client requests both the fake and real front-buffer.
+            */
+           if (attachment == DRI2BufferBackLeft) {
+               need_real_front++;
+               front_format = format;
+           }
 
-       buffers[i] = allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
-                                             format, dimensions_match);
+           if (attachment == DRI2BufferFrontLeft) {
+               need_real_front--;
+               front_format = format;
 
+               if (pDraw->type == DRAWABLE_WINDOW) {
+                   need_fake_front++;
+               }
+           }
 
-       /* If the drawable is a window and the front-buffer is requested,
-        * silently add the fake front-buffer to the list of requested
-        * attachments.  The counting logic in the loop accounts for the case
-        * where the client requests both the fake and real front-buffer.
-        */
-       if (attachment == DRI2BufferBackLeft) {
-           need_real_front++;
-           front_format = format;
+           if (pDraw->type == DRAWABLE_WINDOW) {
+               if (attachment == DRI2BufferFakeFrontLeft) {
+                   need_fake_front--;
+                   have_fake_front = 1;
+               }
+           }
        }
 
-       if (attachment == DRI2BufferFrontLeft) {
-           need_real_front--;
-           front_format = format;
+       if (need_real_front > 0) {
+           buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
+                                                   DRI2BufferFrontLeft,
+                                                   front_format, 
dimensions_match);
+       }
 
-           if (pDraw->type == DRAWABLE_WINDOW) {
-               need_fake_front++;
+       if (need_fake_front > 0) {
+           buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
+                                                   DRI2BufferFakeFrontLeft,
+                                                   front_format, 
dimensions_match);
+           have_fake_front = 1;
+       }
+
+       *out_count = i;
+
+
+       if (pPriv->buffers != NULL) {
+           for (i = 0; i < pPriv->bufferCount; i++) {
+               if (pPriv->buffers[i] != NULL) {
+                   (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
+               }
            }
+
+           xfree(pPriv->buffers);
+       }
+    } else {
+       DRI2BufferPtr   buffers1;
+       unsigned int    temp_buf[32];
+       unsigned int    *temp = temp_buf;
+       int             i;
+       int             buffers_match = 1;
+
+       /* Version 1 API with CreateBuffers */
+
+       if ((count + 1) > 32) {
+           temp = xalloc((count + 1) * sizeof(temp[0]));
        }
 
-       if (pDraw->type == DRAWABLE_WINDOW) {
-           if (attachment == DRI2BufferFakeFrontLeft) {
+       for (i = 0; i < count; i++) {
+           const unsigned attachment = *(attachments++);
+
+           /* Version 1 doesn't deal with the format at all */
+           if (has_format)
+               attachments++;
+
+           /*
+            * Make sure the client also gets the front buffer when
+            * it asks for a back buffer
+            */
+           if (attachment == DRI2BufferBackLeft)
+               need_real_front++;
+
+           /*
+            * If the drawable is a window and the front-buffer is requested,
+            * silently add the fake front-buffer to the list of requested
+            * attachments.  The counting logic in the loop accounts for the
+            * case where the client requests both the fake and real
+            * front-buffer.
+            */
+           if (attachment == DRI2BufferFrontLeft) {
+               need_real_front--;
+               if (pDraw->type == DRAWABLE_WINDOW)
+                   need_fake_front++;
+           }
+           if (pDraw->type == DRAWABLE_WINDOW &&
+               attachment == DRI2BufferFakeFrontLeft)
+           {
                need_fake_front--;
                have_fake_front = 1;
            }
+
+           temp[i] = attachment;
        }
-    }
 
-    if (need_real_front > 0) {
-       buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
-                                               DRI2BufferFrontLeft,
-                                               front_format, dimensions_match);
-    }
+       if (need_real_front > 0)
+           temp[count++] = DRI2BufferFrontLeft;
 
-    if (need_fake_front > 0) {
-       buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
-                                               DRI2BufferFakeFrontLeft,
-                                               front_format, dimensions_match);
-       have_fake_front = 1;
-    }
+       if (need_fake_front > 0) {
+           temp[count++] = DRI2BufferFakeFrontLeft;
+           have_fake_front = 1;
+       }
 
-    *out_count = i;
+       if (count != pPriv->bufferCount)
+           buffers_match = 0;
+       else {
+           for (i = 0; i < count; i++)
+               if (pPriv->buffers[i]->attachment != temp[i]) {
+                   buffers_match = 0;
+                   break;
+               }
+       }
+       if (pPriv->buffers == NULL || !dimensions_match || !buffers_match)
+       {
+            buffers1 = (*ds->CreateBuffers)(pDraw, temp, count);
+           if (pPriv->buffers != NULL)
+               (*ds->DestroyBuffers)(pDraw, (DRI2BufferPtr) pPriv->buffers[0],
+                                     pPriv->bufferCount);
+       }
+       else
+           buffers1 = (DRI2BufferPtr) pPriv->buffers[0];
 
+        for (i = 0; i < count; i++)
+           buffers[i] = (DRI2Buffer2Ptr) &buffers1[i];
 
-    if (pPriv->buffers != NULL) {
-       for (i = 0; i < pPriv->bufferCount; i++) {
-           if (pPriv->buffers[i] != NULL) {
-               (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
-           }
-       }
+        *out_count = count;
 
-       xfree(pPriv->buffers);
-    }
+       if (pPriv->buffers)
+           xfree (pPriv->buffers);
 
+       if (temp != temp_buf) {
+           xfree(temp);
+       }
+    }
 
     pPriv->buffers = buffers;
     pPriv->bufferCount = *out_count;
@@ -284,7 +375,7 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
     return pPriv->buffers;
 }
 
-DRI2BufferPtr *
+DRI2Buffer2Ptr *
 DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
               unsigned int *attachments, int count, int *out_count)
 {
@@ -292,7 +383,7 @@ DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
                          out_count, FALSE);
 }
 
-DRI2BufferPtr *
+DRI2Buffer2Ptr *
 DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
                         unsigned int *attachments, int count, int *out_count)
 {
@@ -318,13 +409,13 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
     for (i = 0; i < pPriv->bufferCount; i++)
     {
        if (pPriv->buffers[i]->attachment == dest)
-           pDestBuffer = pPriv->buffers[i];
+           pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
        if (pPriv->buffers[i]->attachment == src)
-           pSrcBuffer = pPriv->buffers[i];
+           pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
     }
     if (pSrcBuffer == NULL || pDestBuffer == NULL)
        return BadValue;
-               
+
     (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer);
 
     return Success;
@@ -341,7 +432,7 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
     pPriv = DRI2GetDrawable(pDraw);
     if (pPriv == NULL)
        return;
-    
+
     pPriv->refCount--;
     if (pPriv->refCount > 0)
        return;
@@ -349,8 +440,13 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
     if (pPriv->buffers != NULL) {
        int i;
 
-       for (i = 0; i < pPriv->bufferCount; i++) {
-           (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
+       if (ds->DestroyBuffer) {
+           for (i = 0; i < pPriv->bufferCount; i++) {
+               (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
+           }
+       } else {
+           (*ds->DestroyBuffers)(pDraw, (DRI2BufferPtr) pPriv->buffers[0],
+                                 pPriv->bufferCount);
        }
 
        xfree(pPriv->buffers);
@@ -409,18 +505,36 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
     if (!ds)
        return FALSE;
 
-    if ((info->version < 2)
-       || (info->CreateBuffer == NULL)
-       || (info->DestroyBuffer == NULL)) {
-       return FALSE;
-    }
-
-
     ds->fd            = info->fd;
     ds->driverName     = info->driverName;
     ds->deviceName     = info->deviceName;
-    ds->CreateBuffer   = info->CreateBuffer;
-    ds->DestroyBuffer  = info->DestroyBuffer;
+
+    /* Prefer the new one-at-a-time buffer API */
+    if (info->version >= 2 && info->CreateBuffer && info->DestroyBuffer) {
+       ds->CreateBuffer   = info->CreateBuffer;
+       ds->DestroyBuffer  = info->DestroyBuffer;
+       ds->CreateBuffers  = NULL;
+       ds->DestroyBuffers = NULL;
+    } else if (info->CreateBuffers && info->DestroyBuffers) {
+       xf86DrvMsg(pScreen->myNum, X_WARNING,
+                  "[DRI2] Version 1 API (broken front buffer rendering)\n");
+       ds->CreateBuffer   = NULL;
+       ds->DestroyBuffer  = NULL;
+       ds->CreateBuffers  = info->CreateBuffers;
+       ds->DestroyBuffers = info->DestroyBuffers;
+    } else {
+       xf86DrvMsg(pScreen->myNum, X_ERROR,
+                  "[DRI2] Missing buffer management functions\n");
+       xfree(ds);
+       return FALSE;
+    }
+
+    if (!info->CopyRegion) {
+       xf86DrvMsg(pScreen->myNum, X_ERROR,
+                  "[DRI2] Missing copy region function\n");
+       xfree(ds);
+       return FALSE;
+    }
     ds->CopyRegion     = info->CopyRegion;
 
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index c9a0d3f..ee5e9d7 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -35,16 +35,27 @@
 
 #include <X11/extensions/dri2tokens.h>
 
+/* Version 1 structure (for ABI compatibility) */
 typedef struct {
     unsigned int attachment;
     unsigned int name;
     unsigned int pitch;
     unsigned int cpp;
     unsigned int flags;
-    unsigned int format;
     void *driverPrivate;
 } DRI2BufferRec, *DRI2BufferPtr;
 
+/* Version 2 structure (with format at the end) */
+typedef struct {
+    unsigned int attachment;
+    unsigned int name;
+    unsigned int pitch;
+    unsigned int cpp;
+    unsigned int flags;
+    void *driverPrivate;
+    unsigned int format;
+} DRI2Buffer2Rec, *DRI2Buffer2Ptr;
+
 typedef DRI2BufferPtr  (*DRI2CreateBuffersProcPtr)(DrawablePtr pDraw,
                                                    unsigned int *attachments,
                                                    int count);
@@ -59,11 +70,11 @@ typedef void                
(*DRI2CopyRegionProcPtr)(DrawablePtr pDraw,
 typedef void           (*DRI2WaitProcPtr)(WindowPtr pWin,
                                           unsigned int sequence);
 
-typedef DRI2BufferPtr  (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
+typedef DRI2Buffer2Ptr (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
                                                   unsigned int attachment,
                                                   unsigned int format);
 typedef void           (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
-                                                   DRI2BufferPtr buffer);
+                                                   DRI2Buffer2Ptr buffer);
 
 /**
  * Version of the DRI2InfoRec structure defined in this header
@@ -108,12 +119,12 @@ int DRI2CreateDrawable(DrawablePtr pDraw);
 
 void DRI2DestroyDrawable(DrawablePtr pDraw);
 
-DRI2BufferPtr *DRI2GetBuffers(DrawablePtr pDraw,
-                            int *width,
-                            int *height,
-                            unsigned int *attachments,
-                            int count,
-                            int *out_count);
+DRI2Buffer2Ptr *DRI2GetBuffers(DrawablePtr pDraw,
+                              int *width,
+                              int *height,
+                              unsigned int *attachments,
+                              int count,
+                              int *out_count);
 
 int DRI2CopyRegion(DrawablePtr pDraw,
                   RegionPtr pRegion,
@@ -138,7 +149,7 @@ int DRI2CopyRegion(DrawablePtr pDraw,
  */
 extern _X_EXPORT void DRI2Version(int *major, int *minor);
 
-extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
+extern _X_EXPORT DRI2Buffer2Ptr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
        int *width, int *height, unsigned int *attachments, int count,
        int *out_count);
 
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index 97b96fa..3c06174 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -196,7 +196,7 @@ ProcDRI2DestroyDrawable(ClientPtr client)
 
 static void
 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
-                  DRI2BufferPtr *buffers, int count, int width, int height)
+                  DRI2Buffer2Ptr *buffers, int count, int width, int height)
 {
     xDRI2GetBuffersReply rep;
     int skip = 0;
@@ -246,7 +246,7 @@ ProcDRI2GetBuffers(ClientPtr client)
 {
     REQUEST(xDRI2GetBuffersReq);
     DrawablePtr pDrawable;
-    DRI2BufferPtr *buffers;
+    DRI2Buffer2Ptr *buffers;
     int status, width, height, count;
     unsigned int *attachments;
 
@@ -269,7 +269,7 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
 {
     REQUEST(xDRI2GetBuffersReq);
     DrawablePtr pDrawable;
-    DRI2BufferPtr *buffers;
+    DRI2Buffer2Ptr *buffers;
     int status, width, height, count;
     unsigned int *attachments;
 
-- 
1.6.3.1

_______________________________________________
xorg-devel mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to