[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, &region, &box, 0);
+
+	DRI2CopyRegion(pDraw, &region, DRI2BufferFrontLeft,
+		       DRI2BufferBackLeft);
+	REGION_UNINIT(pScreen, &region);
+
+	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