This change implements the protocol for DRI2GetBuffersWithFormat, but
the bulk of the differences are the changes to the extension / driver
interface to make this function work.  The old CreateBuffers and
DeleteBuffers routines are replaced with CreateBuffer and DeleteBuffer
(both singular).

This allows drivers to allocate buffers for a drawable one at a time.
As a result, 3D drivers can now allocate the (fake) front-buffer for a
window only when it is needed.  Since 3D drivers only ask for the
front-buffer on demand, the real front-buffer is always created.  This
allows CopyRegion impelemenations of SwapBuffers to continue working.
As with previous version of this code, if the client asks for the
front-buffer for a window, we instead give it the fake front-buffer.

Signed-off-by: Ian Romanick <[email protected]>
---
 configure.ac              |    2 +-
 glx/glxdri2.c             |   59 ++++++++++++--
 hw/xfree86/dri2/dri2.c    |  195 +++++++++++++++++++++++++++++++++------------
 hw/xfree86/dri2/dri2.h    |   22 +++++-
 hw/xfree86/dri2/dri2ext.c |   88 ++++++++++++++------
 5 files changed, 278 insertions(+), 88 deletions(-)

diff --git a/configure.ac b/configure.ac
index ef50627..2a73d8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -886,7 +886,7 @@ if test "x$DRI" = xyes; then
        AC_SUBST(DRIPROTO_CFLAGS)
 fi
 
-PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= 1.99.3],
+PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= 2.1],
                   [HAVE_DRI2PROTO=yes], [HAVE_DRI2PROTO=no])
 case "$DRI2,$HAVE_DRI2PROTO" in
        yes,no)
diff --git a/glx/glxdri2.c b/glx/glxdri2.c
index 612defb..529b2df 100644
--- a/glx/glxdri2.c
+++ b/glx/glxdri2.c
@@ -406,7 +406,7 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
               int *out_count, void *loaderPrivate)
 {
     __GLXDRIdrawable *private = loaderPrivate;
-    DRI2BufferPtr buffers;
+    DRI2BufferPtr *buffers;
     int i;
     int j;
 
@@ -427,15 +427,59 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
        /* Do not send the real front buffer of a window to the client.
         */
        if ((private->base.pDraw->type == DRAWABLE_WINDOW)
-           && (buffers[i].attachment == DRI2BufferFrontLeft)) {
+           && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
            continue;
        }
 
-       private->buffers[j].attachment = buffers[i].attachment;
-       private->buffers[j].name = buffers[i].name;
-       private->buffers[j].pitch = buffers[i].pitch;
-       private->buffers[j].cpp = buffers[i].cpp;
-       private->buffers[j].flags = buffers[i].flags;
+       private->buffers[j].attachment = buffers[i]->attachment;
+       private->buffers[j].name = buffers[i]->name;
+       private->buffers[j].pitch = buffers[i]->pitch;
+       private->buffers[j].cpp = buffers[i]->cpp;
+       private->buffers[j].flags = buffers[i]->flags;
+       j++;
+    }
+
+    *out_count = j;
+    return private->buffers;
+}
+
+static __DRIbuffer *
+dri2GetBuffersWithFormat(__DRIdrawable *driDrawable,
+                        int *width, int *height,
+                        unsigned int *attachments, int count,
+                        int *out_count, void *loaderPrivate)
+{
+    __GLXDRIdrawable *private = loaderPrivate;
+    DRI2BufferPtr *buffers;
+    int i;
+    int j = 0;
+
+    buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
+                                      width, height, attachments, count,
+                                      out_count);
+    if (*out_count > MAX_DRAWABLE_BUFFERS) {
+       *out_count = 0;
+       return NULL;
+    }
+
+    private->width = *width;
+    private->height = *height;
+
+    /* This assumes the DRI2 buffer attachment tokens matches the
+     * __DRIbuffer tokens. */
+    for (i = 0; i < *out_count; i++) {
+       /* Do not send the real front buffer of a window to the client.
+        */
+       if ((private->base.pDraw->type == DRAWABLE_WINDOW)
+           && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
+           continue;
+       }
+
+       private->buffers[j].attachment = buffers[i]->attachment;
+       private->buffers[j].name = buffers[i]->name;
+       private->buffers[j].pitch = buffers[i]->pitch;
+       private->buffers[j].cpp = buffers[i]->cpp;
+       private->buffers[j].flags = buffers[i]->flags;
        j++;
     }
 
@@ -454,6 +498,7 @@ static const __DRIdri2LoaderExtension loaderExtension = {
     { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION },
     dri2GetBuffers,
     dri2FlushFrontBuffer,
+    dri2GetBuffersWithFormat,
 };
 
 static const __DRIextension *loader_extensions[] = {
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 0b52a0f..9f9ec9d 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;
+    DRI2BufferPtr      *buffers;
     int                         bufferCount;
     unsigned int        pendingSequence;
 } DRI2DrawableRec, *DRI2DrawablePtr;
@@ -63,8 +63,8 @@ typedef struct _DRI2Screen {
     const char                 *deviceName;
     int                                 fd;
     unsigned int                lastSequence;
-    DRI2CreateBuffersProcPtr    CreateBuffers;
-    DRI2DestroyBuffersProcPtr   DestroyBuffers;
+    DRI2CreateBufferProcPtr     CreateBuffer;
+    DRI2DestroyBufferProcPtr    DestroyBuffer;
     DRI2CopyRegionProcPtr       CopyRegion;
 
     HandleExposuresProcPtr       HandleExposures;
@@ -132,71 +132,130 @@ DRI2CreateDrawable(DrawablePtr pDraw)
     return Success;
 }
 
-DRI2BufferPtr
-DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
-              unsigned int *attachments, int count, int *out_count)
+static int
+find_attachment(DRI2BufferPtr *buffer_list, int count, unsigned attachment)
+{
+    int i;
+
+    if (buffer_list == NULL) {
+       return -1;
+    }
+
+    for (i = 0; i < count; i++) {
+       if ((buffer_list[i] != NULL)
+           && (buffer_list[i]->attachment == attachment)) {
+           return i;
+       }
+    }
+
+    return -1;
+}
+
+static DRI2BufferPtr
+allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
+                        DRI2DrawablePtr pPriv,
+                        unsigned int attachment, unsigned int format,
+                        int dimensions_match)
+{
+    DRI2BufferPtr buffer;
+    int old_buf;
+
+    old_buf = find_attachment(pPriv->buffers, pPriv->bufferCount, attachment);
+
+    if ((old_buf < 0)
+       || !dimensions_match
+       || (pPriv->buffers[old_buf]->format != format)) {
+       buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
+    } else {
+       buffer = pPriv->buffers[old_buf];
+       pPriv->buffers[old_buf] = NULL;
+    }
+
+    return buffer;
+}
+
+static DRI2BufferPtr *
+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;
-    unsigned int temp_buf[32];
-    unsigned int *temp = temp_buf;
+    DRI2BufferPtr  *buffers;
+    int need_real_front = 0;
+    int need_fake_front = 0;
     int have_fake_front = 0;
+    int front_format = 0;
+    const int dimensions_match = (pDraw->width == pPriv->width)
+       && (pDraw->height == pPriv->height);
+    int i;
 
 
-    /* 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 (pDraw->type == DRAWABLE_WINDOW) {
-       int need_fake_front = 0;
-       int i;
+    buffers = xalloc((count + 1) * sizeof(buffers[0]));
 
-       if ((count + 1) > 32) {
-           temp = xalloc((count + 1) * sizeof(temp[0]));
-       }
+    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);
 
-       for (i = 0; i < count; i++) {
-           if (attachments[i] == DRI2BufferFrontLeft) {
+
+       /* 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 (pDraw->type == DRAWABLE_WINDOW) {
+           if (attachment == DRI2BufferBackLeft) {
+               need_real_front++;
+               front_format = format;
+           }
+
+           if (attachment == DRI2BufferFrontLeft) {
+               need_real_front--;
                need_fake_front++;
+               front_format = format;
            }
 
-           if (attachments[i] == DRI2BufferFakeFrontLeft) {
+           if (attachment == DRI2BufferFakeFrontLeft) {
                need_fake_front--;
                have_fake_front = 1;
            }
-
-           temp[i] = attachments[i];
-       }
-
-       if (need_fake_front > 0) {
-           temp[i] = DRI2BufferFakeFrontLeft;
-           count++;
-           have_fake_front = 1;
-           attachments = temp;
        }
     }
 
+    if (need_real_front > 0) {
+       buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
+                                               DRI2BufferFrontLeft,
+                                               front_format, dimensions_match);
+    }
 
-    if (pPriv->buffers == NULL ||
-       pDraw->width != pPriv->width || pDraw->height != pPriv->height)
-    {
-       buffers = (*ds->CreateBuffers)(pDraw, attachments, count);
-       (*ds->DestroyBuffers)(pDraw, pPriv->buffers, pPriv->bufferCount);
-       pPriv->buffers = buffers;
-       pPriv->bufferCount = count;
-       pPriv->width = pDraw->width;
-       pPriv->height = pDraw->height;
+    if (need_fake_front > 0) {
+       buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv,
+                                               DRI2BufferFakeFrontLeft,
+                                               front_format, dimensions_match);
+       have_fake_front = 1;
     }
 
-    if (temp != temp_buf) {
-       xfree(temp);
+    *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);
     }
 
+
+    pPriv->buffers = buffers;
+    pPriv->bufferCount = *out_count;
     *width = pPriv->width;
     *height = pPriv->height;
-    *out_count = pPriv->bufferCount;
 
 
     /* If the client is getting a fake front-buffer, pre-fill it with the
@@ -220,6 +279,22 @@ DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
     return pPriv->buffers;
 }
 
+DRI2BufferPtr *
+DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
+              unsigned int *attachments, int count, int *out_count)
+{
+    return do_get_buffers(pDraw, width, height, attachments, count,
+                         out_count, FALSE);
+}
+
+DRI2BufferPtr *
+DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
+                        unsigned int *attachments, int count, int *out_count)
+{
+    return do_get_buffers(pDraw, width, height, attachments, count,
+                         out_count, TRUE);
+}
+
 int
 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
               unsigned int dest, unsigned int src)
@@ -237,10 +312,10 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
     pSrcBuffer = NULL;
     for (i = 0; i < pPriv->bufferCount; i++)
     {
-       if (pPriv->buffers[i].attachment == dest)
-           pDestBuffer = &pPriv->buffers[i];
-       if (pPriv->buffers[i].attachment == src)
-           pSrcBuffer = &pPriv->buffers[i];
+       if (pPriv->buffers[i]->attachment == dest)
+           pDestBuffer = pPriv->buffers[i];
+       if (pPriv->buffers[i]->attachment == src)
+           pSrcBuffer = pPriv->buffers[i];
     }
     if (pSrcBuffer == NULL || pDestBuffer == NULL)
        return BadValue;
@@ -266,7 +341,16 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
     if (pPriv->refCount > 0)
        return;
 
-    (*ds->DestroyBuffers)(pDraw, pPriv->buffers, pPriv->bufferCount);
+    if (pPriv->buffers != NULL) {
+       int i;
+
+       for (i = 0; i < pPriv->bufferCount; i++) {
+           (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
+       }
+
+       xfree(pPriv->buffers);
+    }
+
     xfree(pPriv);
 
     if (pDraw->type == DRAWABLE_WINDOW)
@@ -320,11 +404,18 @@ 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->CreateBuffers  = info->CreateBuffers;
-    ds->DestroyBuffers = info->DestroyBuffers;
+    ds->CreateBuffer   = info->CreateBuffer;
+    ds->DestroyBuffer  = info->DestroyBuffer;
     ds->CopyRegion     = info->CopyRegion;
 
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
@@ -371,7 +462,7 @@ static XF86ModuleVersionInfo DRI2VersRec =
     MODINFOSTRING1,
     MODINFOSTRING2,
     XORG_VERSION_CURRENT,
-    1, 0, 0,
+    1, 1, 0,
     ABI_CLASS_EXTENSION,
     ABI_EXTENSION_VERSION,
     MOD_CLASS_NONE,
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index 847e57c..53fe888 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -41,6 +41,7 @@ typedef struct {
     unsigned int pitch;
     unsigned int cpp;
     unsigned int flags;
+    unsigned int format;
     void *driverPrivate;
 } DRI2BufferRec, *DRI2BufferPtr;
 
@@ -58,8 +59,19 @@ typedef void         (*DRI2CopyRegionProcPtr)(DrawablePtr 
pDraw,
 typedef void           (*DRI2WaitProcPtr)(WindowPtr pWin,
                                           unsigned int sequence);
 
+typedef DRI2BufferPtr  (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
+                                                  unsigned int attachment,
+                                                  unsigned int format);
+typedef void           (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
+                                                   DRI2BufferPtr buffer);
+
+/**
+ * Version of the DRI2InfoRec structure defined in this header
+ */
+#define DRI2INFOREC_VERSION 2
+
 typedef struct {
-    unsigned int version;      /* Version of this struct */
+    unsigned int version;      /**< Version of this struct */
     int fd;
     const char *driverName;
     const char *deviceName;
@@ -68,6 +80,8 @@ typedef struct {
     DRI2DestroyBuffersProcPtr  DestroyBuffers;
     DRI2CopyRegionProcPtr      CopyRegion;
     DRI2WaitProcPtr            Wait;
+    DRI2CreateBufferProcPtr    CreateBuffer;
+    DRI2DestroyBufferProcPtr   DestroyBuffer;
 
 }  DRI2InfoRec, *DRI2InfoPtr;
 
@@ -88,7 +102,7 @@ extern _X_EXPORT int DRI2CreateDrawable(DrawablePtr pDraw);
 
 extern _X_EXPORT void DRI2DestroyDrawable(DrawablePtr pDraw);
 
-extern _X_EXPORT DRI2BufferPtr DRI2GetBuffers(DrawablePtr pDraw,
+extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffers(DrawablePtr pDraw,
                             int *width,
                             int *height,
                             unsigned int *attachments,
@@ -100,4 +114,8 @@ extern _X_EXPORT int DRI2CopyRegion(DrawablePtr pDraw,
                   unsigned int dest,
                   unsigned int src);
 
+extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
+       int *width, int *height, unsigned int *attachments, int count,
+       int *out_count);
+
 #endif
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index 23f3121..029dce8 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -80,7 +80,7 @@ ProcDRI2QueryVersion(ClientPtr client)
     rep.length = 0;
     rep.sequenceNumber = client->sequence;
     rep.majorVersion = 1;
-    rep.minorVersion = 0;
+    rep.minorVersion = 1;
 
     if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
@@ -192,32 +192,20 @@ ProcDRI2DestroyDrawable(ClientPtr client)
     return client->noClientException;
 }
 
-static int
-ProcDRI2GetBuffers(ClientPtr client)
+
+static void
+send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
+                  DRI2BufferPtr *buffers, int count, int width, int height)
 {
-    REQUEST(xDRI2GetBuffersReq);
     xDRI2GetBuffersReply rep;
-    DrawablePtr pDrawable;
-    DRI2BufferPtr buffers;
-    int i, status, width, height, count;
-    unsigned int *attachments;
-    xDRI2Buffer buffer;
-    int skip;
+    int skip = 0;
+    int i;
 
-    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
-    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
-       return status;
-
-    attachments = (unsigned int *) &stuff[1];
-    buffers = DRI2GetBuffers(pDrawable, &width, &height,
-                            attachments, stuff->count, &count);
-
-    skip = 0;
     if (pDrawable->type == DRAWABLE_WINDOW) {
        for (i = 0; i < count; i++) {
            /* Do not send the real front buffer of a window to the client.
             */
-           if (buffers[i].attachment == DRI2BufferFrontLeft) {
+           if (buffers[i]->attachment == DRI2BufferFrontLeft) {
                skip++;
                continue;
            }
@@ -233,20 +221,66 @@ ProcDRI2GetBuffers(ClientPtr client)
     WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
 
     for (i = 0; i < count; i++) {
+       xDRI2Buffer buffer;
+
        /* Do not send the real front buffer of a window to the client.
         */
        if ((pDrawable->type == DRAWABLE_WINDOW)
-           && (buffers[i].attachment == DRI2BufferFrontLeft)) {
+           && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
            continue;
        }
 
-       buffer.attachment = buffers[i].attachment;
-       buffer.name = buffers[i].name;
-       buffer.pitch = buffers[i].pitch;
-       buffer.cpp = buffers[i].cpp;
-       buffer.flags = buffers[i].flags;
+       buffer.attachment = buffers[i]->attachment;
+       buffer.name = buffers[i]->name;
+       buffer.pitch = buffers[i]->pitch;
+       buffer.cpp = buffers[i]->cpp;
+       buffer.flags = buffers[i]->flags;
        WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
     }
+}
+
+
+static int
+ProcDRI2GetBuffers(ClientPtr client)
+{
+    REQUEST(xDRI2GetBuffersReq);
+    DrawablePtr pDrawable;
+    DRI2BufferPtr *buffers;
+    int status, width, height, count;
+    unsigned int *attachments;
+
+    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
+    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
+       return status;
+
+    attachments = (unsigned int *) &stuff[1];
+    buffers = DRI2GetBuffers(pDrawable, &width, &height,
+                            attachments, stuff->count, &count);
+
+
+    send_buffers_reply(client, pDrawable, buffers, count, width, height);
+
+    return client->noClientException;
+}
+
+static int
+ProcDRI2GetBuffersWithFormat(ClientPtr client)
+{
+    REQUEST(xDRI2GetBuffersReq);
+    DrawablePtr pDrawable;
+    DRI2BufferPtr *buffers;
+    int status, width, height, count;
+    unsigned int *attachments;
+
+    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
+    if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
+       return status;
+
+    attachments = (unsigned int *) &stuff[1];
+    buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
+                                      attachments, stuff->count, &count);
+
+    send_buffers_reply(client, pDrawable, buffers, count, width, height);
 
     return client->noClientException;
 }
@@ -313,6 +347,8 @@ ProcDRI2Dispatch (ClientPtr client)
        return ProcDRI2GetBuffers(client);
     case X_DRI2CopyRegion:
        return ProcDRI2CopyRegion(client);
+    case X_DRI2GetBuffersWithFormat:
+       return ProcDRI2GetBuffersWithFormat(client);
     default:
        return BadRequest;
     }
-- 
1.6.0.6

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

Reply via email to