[Intel-gfx] [PATCH] xf86-video-intel: support swapbuffers using page flipping

Jesse Barnes jbarnes at virtuousgeek.org
Thu Feb 26 22:36:26 CET 2009


Support the new swapbuffers request using the new page flipping ioctl
if possible.

This patch still needs some work; there's a bug in the no-flip case that
causes us to lose track of pixmaps, and the pipe is still hardcoded to 1,
but that should be easy to fix.

The code is pretty ugly too; it seems like getbuffers and swapbuffers could
probably share more code, but we need to copy all the buffers in swapbuffers
to return them...

diff --git a/src/i830.h b/src/i830.h
index 7904b9f..5c65ce8 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_bios.c b/src/i830_bios.c
index 6baacd4..72408f0 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -135,12 +135,6 @@ parse_panel_data(I830Ptr pI830, struct bdb_header *bdb)
     fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000;
     fixed_mode->type       = M_T_PREFERRED;
 
-    /* Some VBTs have bogus h/vtotal values */
-    if (fixed_mode->HSyncEnd > fixed_mode->HTotal)
-	fixed_mode->HTotal = fixed_mode->HSyncEnd + 1;
-    if (fixed_mode->VSyncEnd > fixed_mode->VTotal)
-	fixed_mode->VTotal = fixed_mode->VSyncEnd + 1;
-
     xf86SetModeDefaultName(fixed_mode);
 
     pI830->lvds_fixed_mode = fixed_mode;
diff --git a/src/i830_display.c b/src/i830_display.c
index 8a5cf24..692349e 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1669,6 +1669,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;
 }
 
@@ -1677,6 +1680,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);
@@ -1687,6 +1691,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..00458b7 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -70,6 +70,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
 
 #include "xf86.h"
 #include "xf86_OSproc.h"
@@ -1537,18 +1539,13 @@ I830DRI2CreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count)
     I830Ptr pI830 = I830PTR(pScrn);
     DRI2BufferPtr buffers;
     dri_bo *bo;
-    int i;
-    I830DRI2BufferPrivatePtr privates;
+    int i, j;
+    I830DRI2BufferPrivatePtr private;
     PixmapPtr pPixmap, pDepthPixmap;
 
     buffers = xcalloc(count, sizeof *buffers);
     if (buffers == NULL)
 	return NULL;
-    privates = xcalloc(count, sizeof *privates);
-    if (privates == NULL) {
-	xfree(buffers);
-	return NULL;
-    }
 
     pDepthPixmap = NULL;
     for (i = 0; i < count; i++) {
@@ -1597,12 +1594,21 @@ I830DRI2CreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count)
 	if (attachments[i] == DRI2BufferDepth)
 	    pDepthPixmap = pPixmap;
 
+	private = xcalloc(1, sizeof *private);
+	if (!private) {
+	    for (j = 0; j < i; j++)
+		xfree(buffers[j].driverPrivate);
+	    xfree(buffers);
+	    return NULL;
+	}
+
+
 	buffers[i].attachment = attachments[i];
 	buffers[i].pitch = pPixmap->devKind;
 	buffers[i].cpp = pPixmap->drawable.bitsPerPixel / 8;
-	buffers[i].driverPrivate = &privates[i];
+	buffers[i].driverPrivate = private;
 	buffers[i].flags = 0; /* not tiled */
-	privates[i].pPixmap = pPixmap;
+	private->pPixmap = pPixmap;
 
 	bo = i830_get_pixmap_bo (pPixmap);
 	if (dri_bo_flink(bo, &buffers[i].name) != 0) {
@@ -1625,11 +1631,11 @@ I830DRI2DestroyBuffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count)
     {
 	private = buffers[i].driverPrivate;
 	(*pScreen->DestroyPixmap)(private->pPixmap);
+	xfree(buffers[i].driverPrivate);
+	buffers[i].driverPrivate = NULL;
     }
 
-    if (buffers)
-    {
-	xfree(buffers[0].driverPrivate);
+    if (buffers) {
 	xfree(buffers);
     }
 }
@@ -1672,6 +1678,168 @@ I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
 
 }
 
+/*
+ * At flip time we need to:
+ *  - 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 Bool
+i830_do_pageflip(DrawablePtr pDraw, DRI2BufferPtr front, DRI2BufferPtr back)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    I830Ptr pI830 = I830PTR(pScrn);
+    int tmp;
+    I830DRI2BufferPrivatePtr front_priv, back_priv;
+    dri_bo *front_bo, *back_bo;
+    struct drm_i915_gem_page_flip flip;
+    int ret;
+
+    front_priv = front->driverPrivate;
+    back_priv = back->driverPrivate;
+    front_bo = i830_get_pixmap_bo(front_priv->pPixmap);
+    back_bo = i830_get_pixmap_bo(back_priv->pPixmap);
+
+    tmp = front->name;
+    front->name = back->name;
+    back->name = tmp;
+    i830_set_pixmap_bo(back_priv->pPixmap, front_bo);
+
+    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;	flip.offset = 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 FALSE;
+	}
+    }
+
+    i830_set_pixmap_bo(pScreen->GetScreenPixmap(pScreen), back_bo);
+
+    return TRUE;
+}
+
+/* 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, DRI2BufferPtr buffers, int count)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    BoxRec box;
+    RegionRec region;
+    DRI2BufferPtr new_buffers, back = NULL, front = NULL;
+    I830DRI2BufferPrivatePtr private, old_priv;
+    PixmapPtr pPixmap, pDepthPixmap = NULL;
+    int i, j;
+    dri_bo *bo;
+
+    new_buffers = xcalloc(count, sizeof *buffers);
+    if (new_buffers == NULL)
+	return NULL;
+
+    for (i = 0; i < count; i++) {
+	old_priv = buffers[i].driverPrivate;
+
+	if (buffers[i].attachment == DRI2BufferFrontLeft) {
+	    if (pDraw->type == DRAWABLE_PIXMAP)
+		pPixmap = (PixmapPtr) pDraw;
+	    else
+		pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
+	    pPixmap->refcnt++;
+	} else if (buffers[i].attachment == DRI2BufferStencil && pDepthPixmap) {
+	    pPixmap = pDepthPixmap;
+	    pPixmap->refcnt++;
+	} else {
+	    pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pDraw->depth, 0);
+	    (*pScreen->ModifyPixmapHeader)(pPixmap, pDraw->width, pDraw->height,
+					   0, 0, buffers[i].pitch, NULL);
+	}
+
+	if (buffers[i].attachment == DRI2BufferDepth)
+	    pDepthPixmap = pPixmap;
+
+	private = xcalloc(1, sizeof *private);
+	if (!private) {
+	    for (j = 0; j < i; j++)
+		xfree(new_buffers[j].driverPrivate);
+	    xfree(new_buffers);
+	    return NULL;
+	}
+
+	new_buffers[i].attachment = buffers[i].attachment;
+	new_buffers[i].pitch = buffers[i].pitch;
+	new_buffers[i].cpp = buffers[i].cpp;
+	new_buffers[i].driverPrivate = private;
+	new_buffers[i].name = buffers[i].name;
+	new_buffers[i].flags = 0; /* not tiled */
+	private->pPixmap = pPixmap;
+
+	bo = i830_get_pixmap_bo(old_priv->pPixmap);
+	dri_bo_reference(bo);
+	i830_set_pixmap_bo(pPixmap, bo);
+
+	if (buffers[i].attachment == DRI2BufferFrontLeft)
+	    front = &new_buffers[i];
+	if (buffers[i].attachment == DRI2BufferBackLeft)
+	    back = &new_buffers[i];
+    }
+
+    if (i830_flip_ok(pDraw)) {
+	/* Page flip the full screen buffer */
+	I830Sync(pScrn);
+	if (i830_do_pageflip(pDraw, front, back))
+	    goto out;
+    }
+
+    /* Fall back to a blit */
+    box.x1 = 0;
+    box.y1 = 0;
+    box.x2 = pDraw->width;
+    box.y2 = pDraw->height;
+    REGION_INIT(pScreen, &region, &box, 0);
+
+    I830DRI2CopyRegion(pDraw, &region, front, back);
+    REGION_UNINIT(pScreen, &region);
+
+out:
+    return new_buffers;
+}
+
 Bool I830DRI2ScreenInit(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
@@ -1742,6 +1910,7 @@ Bool I830DRI2ScreenInit(ScreenPtr pScreen)
     info.CreateBuffers = I830DRI2CreateBuffers;
     info.DestroyBuffers = I830DRI2DestroyBuffers;
     info.CopyRegion = I830DRI2CopyRegion;
+    info.SwapBuffers = I830DRI2SwapBuffers;
 
     pI830->drmSubFD = info.fd;
 
diff --git a/src/i830_exa.c b/src/i830_exa.c
index ebc6624..972d1f1 100644
--- a/src/i830_exa.c
+++ b/src/i830_exa.c
@@ -921,7 +921,7 @@ i830_uxa_destroy_pixmap (PixmapPtr pixmap)
 	dri_bo  *bo = i830_get_pixmap_bo (pixmap);
     
 	if (bo)
-	    dri_bo_unreference (bo);
+	    ;//dri_bo_unreference (bo);
     }
     fbDestroyPixmap (pixmap);
     return TRUE;




More information about the Intel-gfx mailing list