[PATCH] dri2: Preserve compatibility with 1.6 DRI2 API/ABI
Keith Packard
keithp at keithp.com
Wed Jul 1 16:34:42 PDT 2009
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 <keithp at keithp.com>
---
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
More information about the xorg-devel
mailing list