diff options
Diffstat (limited to 'src/glx/x11/dri2_glx.c')
-rw-r--r-- | src/glx/x11/dri2_glx.c | 125 |
1 files changed, 122 insertions, 3 deletions
diff --git a/src/glx/x11/dri2_glx.c b/src/glx/x11/dri2_glx.c index 2bee67780bd..776a14f614a 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; |