On Thursday, February 26, 2009 1:36:26 pm Jesse Barnes wrote:
> 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...

This version is a little better, and with the X server fix I just posted it
no longer crashes with current compiz.  There are two open issues left:
  1) how to deal with pinning the new front & unpinning the old back
  2) figure out why mixed SwapBuffers/CopyRegion code (e.g. current compiz)
     render right; the front buffer doesn't get any rendering

Problem (2) is probably something simple I'm missing in the flip code, but
(1) is a little trickier.  We need to keep the new front buffer pinned until
the next swap, but the old buffer has to be kept pinned until the swap
completes; one ugly option would be to pass both buffers into the flip ioctl
and let the kernel take care of it.  Any opinions?

Thanks,
-- 
Jesse Barnes, Intel Open Source Technology Center

 i830.h         |    1
 i830_display.c |    5 +
 i830_dri.c     |  188 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 182 insertions(+), 12 deletions(-)

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_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..1c25b81 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,163 @@ 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);
+    I830DRI2BufferPrivatePtr front_priv, back_priv;
+    dri_bo *front_bo, *back_bo;
+    struct drm_i915_gem_page_flip flip;
+    int ret, tmp_name;
+
+    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);
+
+    i830_set_pixmap_bo(front_priv->pPixmap, back_bo);
+    i830_set_pixmap_bo(back_priv->pPixmap, front_bo);
+
+    tmp_name = front->name;
+    front->name = back->name;
+    back->name = tmp_name;
+
+    dri_bo_pin(back_bo, 0);
+
+    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;
+       }
+    }
+
+    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];
+    DRI2BufferPtr new_buffers;
+    I830DRI2BufferPrivatePtr private, old_priv;
+    PixmapPtr pPixmap, pDepthPixmap = NULL;
+    int i, j, front = 0, back = 1;
+    dri_bo *bo;
+
+    if (!i830_flip_ok(pDraw))
+       return NULL;
+
+    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 = i;
+       if (buffers[i].attachment == DRI2BufferBackLeft)
+           back = i;
+    }
+
+    /* Page flip the full screen buffer */
+    I830Sync(pScrn);
+    if (!i830_do_pageflip(pDraw, &new_buffers[front], &new_buffers[back])) {
+       for (i = 0; i < count; i++)
+           xfree(new_buffers[i].driverPrivate);
+       xfree(new_buffers);
+       return NULL;
+    }
+
+    return new_buffers;
+}
+
 Bool I830DRI2ScreenInit(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
@@ -1742,6 +1905,7 @@ Bool I830DRI2ScreenInit(ScreenPtr pScreen)
     info.CreateBuffers = I830DRI2CreateBuffers;
     info.DestroyBuffers = I830DRI2DestroyBuffers;
     info.CopyRegion = I830DRI2CopyRegion;
+    info.SwapBuffers = I830DRI2SwapBuffers;
 
     pI830->drmSubFD = info.fd;
 


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to