summaryrefslogtreecommitdiff
path: root/src/glx/x11/dri2_glx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/x11/dri2_glx.c')
-rw-r--r--src/glx/x11/dri2_glx.c125
1 files changed, 122 insertions, 3 deletions
diff --git a/src/glx/x11/dri2_glx.c b/src/glx/x11/dri2_glx.c
index 2bee67780b..776a14f614 100644
--- a/src/glx/x11/dri2_glx.c
+++ b/src/glx/x11/dri2_glx.c
@@ -60,6 +60,9 @@ struct __GLXDRIdisplayPrivateRec {
int driMajor;
int driMinor;
int driPatch;
+
+ unsigned long configureSeqno;
+ Bool (*oldConfigProc)(Display *, XEvent *, xEvent *);
};
struct __GLXDRIcontextPrivateRec {
@@ -73,6 +76,10 @@ struct __GLXDRIdrawablePrivateRec {
__DRIbuffer buffers[5];
int bufferCount;
int width, height;
+ unsigned long configureSeqno;
+ int have_back;
+ int have_front;
+ int have_fake_front;
};
static void dri2DestroyContext(__GLXDRIcontext *context,
@@ -166,6 +173,8 @@ static __GLXDRIdrawable *dri2CreateDrawable(__GLXscreenConfigs *psc,
pdraw->base.xDrawable = xDrawable;
pdraw->base.drawable = drawable;
pdraw->base.psc = psc;
+ pdraw->bufferCount = 0;
+ pdraw->configureSeqno = ~0;
DRI2CreateDrawable(psc->dpy, xDrawable);
@@ -190,6 +199,10 @@ static void dri2CopySubBuffer(__GLXDRIdrawable *pdraw,
XRectangle xrect;
XserverRegion region;
+ /* Check we have the right attachments */
+ if (!(priv->have_front && priv->have_back))
+ return;
+
xrect.x = x;
xrect.y = priv->height - y - height;
xrect.width = width;
@@ -208,6 +221,47 @@ static void dri2SwapBuffers(__GLXDRIdrawable *pdraw)
dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
}
+static void dri2WaitX(__GLXDRIdrawable *pdraw)
+{
+ __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw;
+ XRectangle xrect;
+ XserverRegion region;
+
+ /* Check we have the right attachments */
+ if (!(priv->have_fake_front && priv->have_front))
+ return;
+
+ xrect.x = 0;
+ xrect.y = 0;
+ xrect.width = priv->width;
+ xrect.height = priv->height;
+
+ region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1);
+ DRI2CopyRegion(pdraw->psc->dpy, pdraw->drawable, region,
+ DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+ XFixesDestroyRegion(pdraw->psc->dpy, region);
+}
+
+static void dri2WaitGL(__GLXDRIdrawable *pdraw)
+{
+ __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw;
+ XRectangle xrect;
+ XserverRegion region;
+
+ if (!(priv->have_fake_front && priv->have_front))
+ return;
+
+ xrect.x = 0;
+ xrect.y = 0;
+ xrect.width = priv->width;
+ xrect.height = priv->height;
+
+ region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1);
+ DRI2CopyRegion(pdraw->psc->dpy, pdraw->drawable, region,
+ DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+ XFixesDestroyRegion(pdraw->psc->dpy, region);
+}
+
static void dri2DestroyScreen(__GLXscreenConfigs *psc)
{
/* Free the direct rendering per screen data */
@@ -223,9 +277,30 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
int *out_count, void *loaderPrivate)
{
__GLXDRIdrawablePrivate *pdraw = loaderPrivate;
+ __GLXdisplayPrivate *dpyPriv = __glXInitialize(pdraw->base.psc->dpy);
+ __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;
DRI2Buffer *buffers;
int i;
+ /**
+ * Check if a ConfigureNotify has come in since we last asked for the
+ * buffers associated with this drawable. If not, we can assume that they're
+ * the same set at glViewport time, and save a synchronous round-trip to the
+ * X Server.
+ */
+ if (pdraw->configureSeqno == pdp->configureSeqno &&
+ count == pdraw->bufferCount) {
+ for (i = 0; i < count; i++) {
+ if (pdraw->buffers[i].attachment != attachments[i])
+ break;
+ }
+ if (i == count) {
+ *out_count = pdraw->bufferCount;
+ return pdraw->buffers;
+ }
+ }
+ pdraw->configureSeqno = pdp->configureSeqno;
+
buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
width, height, attachments, count, out_count);
if (buffers == NULL)
@@ -233,6 +308,10 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
pdraw->width = *width;
pdraw->height = *height;
+ pdraw->bufferCount = *out_count;
+ pdraw->have_front = 0;
+ pdraw->have_fake_front = 0;
+ pdraw->have_back = 0;
/* This assumes the DRI2 buffer attachment tokens matches the
* __DRIbuffer tokens. */
@@ -242,6 +321,12 @@ dri2GetBuffers(__DRIdrawable *driDrawable,
pdraw->buffers[i].pitch = buffers[i].pitch;
pdraw->buffers[i].cpp = buffers[i].cpp;
pdraw->buffers[i].flags = buffers[i].flags;
+ if (pdraw->buffers[i].attachment == __DRI_BUFFER_FRONT_LEFT)
+ pdraw->have_front = 1;
+ if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
+ pdraw->have_fake_front = 1;
+ if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
+ pdraw->have_back = 1;
}
Xfree(buffers);
@@ -282,8 +367,10 @@ static __GLXDRIscreen *dri2CreateScreen(__GLXscreenConfigs *psc, int screen,
return NULL;
psc->driver = driOpenDriver(driverName);
- if (psc->driver == NULL)
+ if (psc->driver == NULL) {
+ ErrorMessageF("driver pointer missing\n");
goto handle_error;
+ }
extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
if (extensions == NULL) {
@@ -309,11 +396,15 @@ static __GLXDRIscreen *dri2CreateScreen(__GLXscreenConfigs *psc, int screen,
return NULL;
}
- if (drmGetMagic(psc->fd, &magic))
+ if (drmGetMagic(psc->fd, &magic)) {
+ ErrorMessageF("failed to get magic\n");
return NULL;
+ }
- if (!DRI2Authenticate(psc->dpy, RootWindow(psc->dpy, screen), magic))
+ if (!DRI2Authenticate(psc->dpy, RootWindow(psc->dpy, screen), magic)) {
+ ErrorMessageF("failed to authenticate magic %d\n", magic);
return NULL;
+ }
psc->__driScreen =
psc->dri2->createNewScreen(screen, psc->fd,
@@ -332,6 +423,8 @@ static __GLXDRIscreen *dri2CreateScreen(__GLXscreenConfigs *psc, int screen,
psp->createContext = dri2CreateContext;
psp->createDrawable = dri2CreateDrawable;
psp->swapBuffers = dri2SwapBuffers;
+ psp->waitGL = dri2WaitGL;
+ psp->waitX = dri2WaitX;
/* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
* available.*/
@@ -359,6 +452,28 @@ static void dri2DestroyDisplay(__GLXDRIdisplay *dpy)
Xfree(dpy);
}
+/**
+ * Makes a note on receiving ConfigureNotify that we need to re-check the
+ * DRI2 buffers, as window sizes may have resulted in reallocation.
+ */
+static Bool dri2ConfigureNotifyProc(Display *dpy, XEvent *re, xEvent *event)
+{
+ __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
+ __GLXDRIdisplayPrivate *pdp;
+ Bool ret;
+
+ /* We should always be able to find our pdp, as it only gets torn down
+ * when the Display is torn down.
+ */
+ pdp = (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display;
+
+ ret = pdp->oldConfigProc(dpy, re, event);
+
+ pdp->configureSeqno = re->xconfigure.serial;
+
+ return ret;
+}
+
/*
* Allocate, initialize and return a __DRIdisplayPrivate object.
* This is called from __glXInitialize() when we are given a new
@@ -381,7 +496,11 @@ _X_HIDDEN __GLXDRIdisplay *dri2CreateDisplay(Display *dpy)
return NULL;
}
+ pdp->oldConfigProc = XESetWireToEvent(dpy, ConfigureNotify,
+ dri2ConfigureNotifyProc);
+
pdp->driPatch = 0;
+ pdp->configureSeqno = 0;
pdp->base.destroyDisplay = dri2DestroyDisplay;
pdp->base.createScreen = dri2CreateScreen;