From 20edb1d61db80f5fedb4d3eea60c67d438502238 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 29 Jul 2009 08:26:14 -0400 Subject: [PATCH] DRI2 Page Flipping --- glx/glxcontext.h | 4 ++ glx/glxdri2.c | 47 ++++++++++++++---- glx/glxext.c | 3 + glx/glxserver.h | 18 +++---- hw/xfree86/dri2/dri2.c | 118 +++++++++++++++++++++++++++++++++++++++++++- hw/xfree86/dri2/dri2.h | 12 ++++- hw/xfree86/dri2/dri2ext.c | 25 +++++++++- 7 files changed, 200 insertions(+), 27 deletions(-) diff --git a/glx/glxcontext.h b/glx/glxcontext.h index 70a1411..79bc083 100644 --- a/glx/glxcontext.h +++ b/glx/glxcontext.h @@ -55,6 +55,10 @@ struct __GLXcontext { unsigned long mask); int (*forceCurrent) (__GLXcontext *context); + Bool (*wait) (__GLXcontext *context, + __GLXclientState *cl, + int *error); + __GLXtextureFromPixmap *textureFromPixmap; /* diff --git a/glx/glxdri2.c b/glx/glxdri2.c index ed7fb4c..4b89c31 100644 --- a/glx/glxdri2.c +++ b/glx/glxdri2.c @@ -70,6 +70,7 @@ struct __GLXDRIscreen { const __DRIcoreExtension *core; const __DRIdri2Extension *dri2; + const __DRI2flushExtension *flush; const __DRIcopySubBufferExtension *copySubBuffer; const __DRIswapControlExtension *swapControl; const __DRItexBufferExtension *texBuffer; @@ -132,17 +133,6 @@ __glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable, DRI2BufferFrontLeft, DRI2BufferBackLeft); } -static GLboolean -__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) -{ - __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; - - __glXDRIdrawableCopySubBuffer(drawable, 0, 0, - private->width, private->height); - - return TRUE; -} - static void __glXDRIdrawableWaitX(__GLXdrawable *drawable) { @@ -177,6 +167,20 @@ __glXDRIdrawableWaitGL(__GLXdrawable *drawable) DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); } +static GLboolean +__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) +{ + __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; + __GLXDRIscreen *screen = priv->screen; + + (*screen->flush->flushInvalidate)(priv->driDrawable); + + if (DRI2SwapBuffers(drawable->pDraw) != Success) + return FALSE; + + return TRUE; +} + static int __glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval) { @@ -241,6 +245,18 @@ __glXDRIcontextForceCurrent(__GLXcontext *baseContext) read->driDrawable); } +static Bool +__glXDRIcontextWait(__GLXcontext *baseContext, + __GLXclientState *cl, int *error) +{ + if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) { + *error = cl->client->noClientException; + return TRUE; + } + + return FALSE; +} + #ifdef __DRI_TEX_BUFFER static int @@ -346,6 +362,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, context->base.copy = __glXDRIcontextCopy; context->base.forceCurrent = __glXDRIcontextForceCurrent; context->base.textureFromPixmap = &__glXDRItextureFromPixmap; + context->base.wait = __glXDRIcontextWait; context->driContext = (*screen->dri2->createNewContext)(screen->driScreen, @@ -581,6 +598,14 @@ initializeExtensions(__GLXDRIscreen *screen) LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); } #endif + +#ifdef __DRI2_FLUSH + if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && + extensions[i]->version >= __DRI2_FLUSH_VERSION) { + screen->flush = (__DRI2flushExtension *) extensions[i]; + } +#endif + /* Ignore unknown extensions */ } } diff --git a/glx/glxext.c b/glx/glxext.c index 19d70d4..f57ccf5 100644 --- a/glx/glxext.c +++ b/glx/glxext.c @@ -439,6 +439,9 @@ __GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag, } } + if (cx->wait && (*cx->wait)(cx, cl, error)) + return NULL; + if (cx == __glXLastContext) { /* No need to re-bind */ return cx; diff --git a/glx/glxserver.h b/glx/glxserver.h index 46c9382..3e62782 100644 --- a/glx/glxserver.h +++ b/glx/glxserver.h @@ -56,7 +56,14 @@ #include #include -/* For glxscreens.h */ +/* +** GLX resources. +*/ +typedef XID GLXContextID; +typedef XID GLXPixmap; +typedef XID GLXDrawable; + +typedef struct __GLXclientStateRec __GLXclientState; typedef struct __GLXdrawable __GLXdrawable; typedef struct __GLXcontext __GLXcontext; @@ -75,15 +82,6 @@ typedef struct __GLXcontext __GLXcontext; #define False 0 #endif -/* -** GLX resources. -*/ -typedef XID GLXContextID; -typedef XID GLXPixmap; -typedef XID GLXDrawable; - -typedef struct __GLXclientStateRec __GLXclientState; - extern __GLXscreen *glxGetScreen(ScreenPtr pScreen); extern __GLXclientState *glxGetClient(ClientPtr pClient); diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index d15ced1..7b9fb23 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c @@ -38,6 +38,7 @@ #include "xf86Module.h" #include "scrnintstr.h" #include "windowstr.h" +#include "dixstruct.h" #include "dri2.h" #include "xf86VGAarbiter.h" @@ -56,7 +57,8 @@ typedef struct _DRI2Drawable { int height; DRI2BufferPtr *buffers; int bufferCount; - unsigned int pendingSequence; + unsigned int swapPending; + ClientPtr blockedClient; } DRI2DrawableRec, *DRI2DrawablePtr; typedef struct _DRI2Screen { @@ -68,6 +70,7 @@ typedef struct _DRI2Screen { DRI2CreateBufferProcPtr CreateBuffer; DRI2DestroyBufferProcPtr DestroyBuffer; DRI2CopyRegionProcPtr CopyRegion; + DRI2SwapBuffersProcPtr SwapBuffers; HandleExposuresProcPtr HandleExposures; } DRI2ScreenRec, *DRI2ScreenPtr; @@ -119,6 +122,8 @@ DRI2CreateDrawable(DrawablePtr pDraw) pPriv->height = pDraw->height; pPriv->buffers = NULL; pPriv->bufferCount = 0; + pPriv->swapPending = FALSE; + pPriv->blockedClient = NULL; if (pDraw->type == DRAWABLE_WINDOW) { @@ -338,6 +343,106 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, return Success; } +static Bool +DRI2FlipCheck(DrawablePtr pDraw) +{ + ScreenPtr pScreen = pDraw->pScreen; + WindowPtr pWin, pRoot; + PixmapPtr pWinPixmap, pRootPixmap; + + if (pDraw->type == DRAWABLE_PIXMAP) + return TRUE; + + pRoot = WindowTable[pScreen->myNum]; + pRootPixmap = pScreen->GetWindowPixmap(pRoot); + + pWin = (WindowPtr) pDraw; + pWinPixmap = pScreen->GetWindowPixmap(pWin); + if (pRootPixmap != pWinPixmap) + return FALSE; + if (!REGION_EQUAL(pScreen, &pWin->clipList, &pRoot->winSize)) + return FALSE; + + return TRUE; +} + +int +DRI2SwapBuffers(DrawablePtr pDraw) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + DRI2DrawablePtr pPriv; + DRI2BufferPtr pDestBuffer, pSrcBuffer; + int i; + BoxRec box; + RegionRec region; + + pPriv = DRI2GetDrawable(pDraw); + if (pPriv == NULL) + return BadDrawable; + + pDestBuffer = NULL; + pSrcBuffer = NULL; + for (i = 0; i < pPriv->bufferCount; i++) + { + if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) + pDestBuffer = pPriv->buffers[i]; + if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) + pSrcBuffer = pPriv->buffers[i]; + } + if (pSrcBuffer == NULL || pDestBuffer == NULL) + return BadValue; + + if (DRI2FlipCheck(pDraw) && + (*ds->SwapBuffers)(pDraw, pDestBuffer, pSrcBuffer, pPriv)) + { + pPriv->swapPending = TRUE; + return Success; + } + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDraw->width; + box.y2 = pDraw->height; + REGION_INIT(drawable->pDraw->pScreen, ®ion, &box, 0); + + return DRI2CopyRegion(pDraw, ®ion, + DRI2BufferFrontLeft, DRI2BufferBackLeft); +} + +Bool +DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) +{ + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); + + /* If we're currently waiting for a swap on this drawable, reset + * the request and suspend the client. We only support one + * blocked client per drawable. */ + if (pPriv->swapPending && pPriv->blockedClient == NULL) { + ResetCurrentRequest(client); + client->sequence--; + IgnoreClient(client); + pPriv->blockedClient = client; + return TRUE; + } + + return FALSE; +} + +void +DRI2SwapComplete(void *data) +{ + DRI2DrawablePtr pPriv = data; + + if (pPriv->blockedClient) + AttendClient(pPriv->blockedClient); + + pPriv->swapPending = FALSE; + pPriv->blockedClient = NULL; + + if (pPriv->refCount == 0) + xfree(pPriv); +} + void DRI2DestroyDrawable(DrawablePtr pDraw) { @@ -363,7 +468,11 @@ DRI2DestroyDrawable(DrawablePtr pDraw) xfree(pPriv->buffers); } - xfree(pPriv); + /* If the window is destroyed while we have a swap pending, don't + * actually free the priv yet. We'll need it in the DRI2SwapComplete() + * callback and we'll free it there once we're done. */ + if (!pPriv->swapPending) + xfree(pPriv); if (pDraw->type == DRAWABLE_WINDOW) { @@ -421,7 +530,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) return FALSE; } - ds = xalloc(sizeof *ds); + ds = xcalloc(1, sizeof *ds); if (!ds) return FALSE; @@ -433,6 +542,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) ds->DestroyBuffer = info->DestroyBuffer; ds->CopyRegion = info->CopyRegion; + if (info->version >= 4) + ds->SwapBuffers = info->SwapBuffers; + dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h index 175471a..42bdb09 100644 --- a/hw/xfree86/dri2/dri2.h +++ b/hw/xfree86/dri2/dri2.h @@ -58,6 +58,10 @@ typedef void (*DRI2CopyRegionProcPtr)(DrawablePtr pDraw, RegionPtr pRegion, DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer); +typedef Bool (*DRI2SwapBuffersProcPtr)(DrawablePtr pDraw, + DRI2BufferPtr pFrontBuffer, + DRI2BufferPtr pBackBuffer, + void *data); typedef void (*DRI2WaitProcPtr)(WindowPtr pWin, unsigned int sequence); @@ -71,7 +75,7 @@ typedef void (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw, /** * Version of the DRI2InfoRec structure defined in this header */ -#define DRI2INFOREC_VERSION 3 +#define DRI2INFOREC_VERSION 4 typedef struct { unsigned int version; /**< Version of this struct */ @@ -82,7 +86,7 @@ typedef struct { DRI2CreateBufferProcPtr CreateBuffer; DRI2DestroyBufferProcPtr DestroyBuffer; DRI2CopyRegionProcPtr CopyRegion; - DRI2WaitProcPtr Wait; + DRI2SwapBuffersProcPtr SwapBuffers; } DRI2InfoRec, *DRI2InfoPtr; @@ -137,4 +141,8 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, unsigned int *attachments, int count, int *out_count); +extern _X_EXPORT int DRI2SwapBuffers(DrawablePtr pDrawable); +extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable); +extern _X_EXPORT void DRI2SwapComplete(void *data); + #endif diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c index 029dce8..9f5f389 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 = 1; + rep.minorVersion = 2; if (client->swapped) { swaps(&rep.sequenceNumber, n); @@ -253,6 +253,9 @@ ProcDRI2GetBuffers(ClientPtr client) if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) return status; + if (DRI2WaitSwap(client, pDrawable)) + return client->noClientException; + attachments = (unsigned int *) &stuff[1]; buffers = DRI2GetBuffers(pDrawable, &width, &height, attachments, stuff->count, &count); @@ -276,6 +279,9 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client) if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) return status; + if (DRI2WaitSwap(client, pDrawable)) + return client->noClientException; + attachments = (unsigned int *) &stuff[1]; buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, attachments, stuff->count, &count); @@ -322,6 +328,21 @@ ProcDRI2CopyRegion(ClientPtr client) } static int +ProcDRI2SwapBuffers(ClientPtr client) +{ + REQUEST(xDRI2SwapBuffersReq); + DrawablePtr pDrawable; + int status; + + REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq); + + if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) + return status; + + return DRI2SwapBuffers(pDrawable); +} + +static int ProcDRI2Dispatch (ClientPtr client) { REQUEST(xReq); @@ -349,6 +370,8 @@ ProcDRI2Dispatch (ClientPtr client) return ProcDRI2CopyRegion(client); case X_DRI2GetBuffersWithFormat: return ProcDRI2GetBuffersWithFormat(client); + case X_DRI2SwapBuffers: + return ProcDRI2SwapBuffers(client); default: return BadRequest; } -- 1.6.0.6