xorg-x11-server/dri2-page-flip.patch
Dave Airlie cdde67c567 * Tue Aug 04 2009 Dave Airlie <airlied@redhat.com> 1.6.99-24.20090804
- update server snapshot + add VGA arbitration
2009-08-04 06:10:29 +00:00

461 lines
13 KiB
Diff

From 20edb1d61db80f5fedb4d3eea60c67d438502238 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Kristian=20H=C3=B8gsberg?= <krh@redhat.com>
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 <GL/gl.h>
#include <GL/glxproto.h>
-/* 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, &region, &box, 0);
+
+ return DRI2CopyRegion(pDraw, &region,
+ 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