[Intel-gfx] [PATCH] xf86-video-intel support for DRI2 buffer swaps
Jesse Barnes
jbarnes at virtuousgeek.org
Fri Feb 13 01:58:05 CET 2009
Fixed it up a bit: we now fall back correctly if pageflipping fails or can't
be done. Also use the new ioctl in the do_pageflip code and check for shadow
framebuffers.
diff --git a/src/i830.h b/src/i830.h
index bfd78dc..607037f 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -452,6 +452,7 @@ typedef struct _I830Rec {
#endif
XF86ModReqInfo shadowReq; /* to test for later libshadow */
+ Bool shadow_present;
Rotation rotation;
void (*PointerMoved)(int, int, int);
CreateScreenResourcesProcPtr CreateScreenResources;
diff --git a/src/i830_display.c b/src/i830_display.c
index 8ecb5e5..ca43537 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1650,6 +1650,9 @@ i830_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
}
if (intel_crtc->rotate_mem && intel_crtc->rotate_mem->bo)
i830_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_mem->bo);
+
+ pI830->shadow_present = TRUE;
+
return rotate_pixmap;
}
@@ -1658,6 +1661,7 @@ i830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
{
ScrnInfoPtr pScrn = crtc->scrn;
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+ I830Ptr pI830 = I830PTR(pScrn);
if (rotate_pixmap)
FreeScratchPixmapHeader(rotate_pixmap);
@@ -1668,6 +1672,7 @@ i830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
i830_free_memory(pScrn, intel_crtc->rotate_mem);
intel_crtc->rotate_mem = NULL;
}
+ pI830->shadow_present = FALSE;
}
#if RANDR_13_INTERFACE
diff --git a/src/i830_dri.c b/src/i830_dri.c
index f03be43..6c44777 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -1672,6 +1672,161 @@ I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
}
+static DRI2BufferPtr
+i830_get_buffer(DrawablePtr pDraw, int attachment)
+{
+ DRI2DrawablePtr pPriv;
+ int i;
+
+ pPriv = DRI2GetDrawable(pDraw);
+ if (!pPriv)
+ return NULL;
+
+ for (i = 0; i < pPriv->bufferCount; i++)
+ if (pPriv->buffers[i].attachment == attachment)
+ return &pPriv->buffers[i];
+
+ return NULL;
+}
+
+/*
+ * At flip time we need to:
+ * - pin the new front buffer
+ * - update X screen pixmap with the new front buffer info
+ * - update new back buffer info with old front buffer info
+ * - queue the flip
+ * - queue a wait so we don't clobber rendering
+ * - return the new front & back buffer info
+ */
+static DRI2BufferPtr
+i830_do_pageflip(DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+ DRI2BufferPtr buffers, dri2_front, dri2_back;
+ I830DRI2BufferPrivatePtr back_priv, front_priv;
+ PixmapPtr tmp;
+ dri_bo *front_bo, *back_bo;
+ struct drm_i915_gem_page_flip flip;
+ int ret;
+
+ dri2_back = i830_get_buffer(pDraw, DRI2BufferBackLeft);
+ dri2_front = i830_get_buffer(pDraw, DRI2BufferFrontLeft);
+ if (!dri2_back || !dri2_front)
+ return NULL;
+
+ back_priv = dri2_back->driverPrivate;
+ back_bo = i830_get_pixmap_bo(back_priv->pPixmap);
+
+ /* This should actually be the screen pixmap */
+ front_priv = dri2_front->driverPrivate;
+ front_bo = i830_get_pixmap_bo(front_priv->pPixmap);
+
+ /* Now do the swap */
+
+ /*
+ * Update the DRI2 buffer with the new info:
+ * - pixmap private ptr (so we can get the buffer later)
+ * - name
+ */
+ tmp = front_priv->pPixmap;
+ front_priv->pPixmap = back_priv->pPixmap;
+ dri_bo_flink(back_bo, &dri2_front->name);
+
+ /* back -> front */
+ back_priv->pPixmap = tmp;
+ dri_bo_flink(front_bo, &dri2_back->name);
+
+ pScrn->fbOffset = back_bo->offset;
+
+ /* If we're in charge of the front buffer, we can flip */
+ if (!pI830->shadow_present) {
+ flip.handle = back_bo->handle;
+ flip.pipe = 1;
+ flip.x = pScrn->virtualX;
+ flip.y = pScrn->virtualY;
+ flip.flags = 0;
+
+ ret = drmCommandWrite(pI830->drmSubFD, DRM_I915_GEM_PAGE_FLIP, &flip,
+ sizeof(flip));
+ if (ret) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+ }
+
+ /* Return the new front & back buffers */
+ buffers = xnfcalloc(sizeof(DRI2BufferRec), 2);
+ buffers[0] = *dri2_front;
+ buffers[1] = *dri2_back;
+
+ return buffers;
+}
+
+/* Check various flip constraints (drawable parameters vs screen params) */
+static Bool
+i830_flip_ok(DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+ if (pDraw->width != pScrn->virtualX)
+ return FALSE;
+ if (pDraw->height != pScrn->virtualY)
+ return FALSE;
+ if (pDraw->depth != pScrn->depth)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * DRI2SwapBuffers should try to do a buffer swap if possible, however:
+ * - if we're swapping buffers smaller than the screen, we have to blit
+ * - if the back buffer doesn't match the screen depth, we have to blit
+ * - otherwise we try to swap, and return to the caller the new front
+ * and back buffers
+ */
+static DRI2BufferPtr
+I830DRI2SwapBuffers(DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+ BoxRec box;
+ RegionRec region;
+ DRI2BufferPtr buffers = NULL, back, front;
+
+ if (i830_flip_ok(pDraw)) {
+ /* Page flip the full screen buffer */
+ I830Sync(pScrn);
+ buffers = i830_do_pageflip(pDraw);
+ }
+
+ /* If the flip failed or we couldn't do it, we need to blit */
+ if (!buffers) {
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pDraw->width;
+ box.y2 = pDraw->height;
+ REGION_INIT(pScreen, ®ion, &box, 0);
+
+ DRI2CopyRegion(pDraw, ®ion, DRI2BufferFrontLeft,
+ DRI2BufferBackLeft);
+ REGION_UNINIT(pScreen, ®ion);
+
+ buffers = xnfcalloc(sizeof(DRI2BufferRec), 2);
+ front = i830_get_buffer(pDraw, DRI2BufferFrontLeft);
+ back = i830_get_buffer(pDraw, DRI2BufferBackLeft);
+ buffers[0] = *front;
+ buffers[1] = *back;
+ }
+
+ return buffers;
+}
+
Bool I830DRI2ScreenInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
@@ -1742,6 +1897,7 @@ Bool I830DRI2ScreenInit(ScreenPtr pScreen)
info.CreateBuffers = I830DRI2CreateBuffers;
info.DestroyBuffers = I830DRI2DestroyBuffers;
info.CopyRegion = I830DRI2CopyRegion;
+ info.SwapBuffers = I830DRI2SwapBuffers;
pI830->drmSubFD = info.fd;
More information about the Intel-gfx
mailing list