From ff6c7764c2909e4126403b7211faa6c58556b341 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 24 Apr 2009 12:49:19 -0700 Subject: [PATCH] DRI2: Implement protocol for DRI2GetBuffersWithFormat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Kristian Høgsberg --- configure.ac | 2 +- glx/glxdri2.c | 59 +++++++++-- hw/xfree86/dri2/dri2.c | 199 +++++++++++++++++++++++++++----------- hw/xfree86/dri2/dri2.h | 28 +++++- hw/xfree86/dri2/dri2ext.c | 88 ++++++++++++----- 5 files changed, 286 insertions(+), 90 deletions(-) diff --git a/configure.ac b/configure.ac index f0317bd76..9eadabced 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 612defb3f..529b2df10 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 80de18f86..9ded048eb 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; - for (i = 0; i < count; i++) { - if (attachments[i] == DRI2BufferFrontLeft) { - need_fake_front++; + 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 (pDraw->type == DRAWABLE_WINDOW) { + if (attachment == DRI2BufferBackLeft) { + need_real_front++; + front_format = format; } - if (attachments[i] == DRI2BufferFakeFrontLeft) { + if (attachment == DRI2BufferFrontLeft) { + need_real_front--; + need_fake_front++; + front_format = format; + } + + 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 (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_real_front > 0) { + buffers[i++] = allocate_or_reuse_buffer(pDraw, ds, pPriv, + DRI2BufferFrontLeft, + front_format, dimensions_match); } - if (temp != temp_buf) { - xfree(temp); + 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); + } + + + 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 9d7d6dc80..b3d02a99e 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; @@ -69,6 +81,14 @@ typedef struct { DRI2CopyRegionProcPtr CopyRegion; DRI2WaitProcPtr Wait; + /** + * \name Fields added in version 2 of the structure. + */ + /*@{*/ + DRI2CreateBufferProcPtr CreateBuffer; + DRI2DestroyBufferProcPtr DestroyBuffer; + /*@}*/ + } DRI2InfoRec, *DRI2InfoPtr; extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr pScreen, @@ -88,7 +108,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, @@ -118,4 +138,8 @@ extern _X_EXPORT int DRI2CopyRegion(DrawablePtr pDraw, */ extern _X_EXPORT void DRI2Version(int *major, int *minor); +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 23f312149..029dce84e 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; }