st/xorg: Add support for dirty framebuffer region reporting.
authorMichel Dänzer <daenzer@vmware.com>
Wed, 26 Aug 2009 11:18:37 +0000 (13:18 +0200)
committerMichel Dänzer <daenzer@vmware.com>
Wed, 26 Aug 2009 11:18:37 +0000 (13:18 +0200)
Add a BlockHandler which flushes the context and reports the dirty region
gathered using the X server damage layer.

In the interim, with dirty region reporting only allocate textures for the
framebuffer and shared pixmaps (e.g. DRI2 buffers) and fall back to software
for other pixmaps. This will be improved in the future.

src/gallium/state_trackers/xorg/xorg_driver.c
src/gallium/state_trackers/xorg/xorg_exa.c
src/gallium/state_trackers/xorg/xorg_tracker.h

index 53d1a33..923662b 100644 (file)
@@ -54,6 +54,7 @@
 
 #include <pciaccess.h>
 
+#include "pipe/p_context.h"
 #include "xorg_tracker.h"
 #include "xorg_winsys.h"
 
@@ -424,6 +425,44 @@ RestoreHWState(ScrnInfoPtr pScrn)
     return TRUE;
 }
 
+static void xorgBlockHandler(int i, pointer blockData, pointer pTimeout,
+                             pointer pReadmask)
+{
+    ScreenPtr pScreen = screenInfo.screens[i];
+    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
+
+    pScreen->BlockHandler = ms->blockHandler;
+    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
+    pScreen->BlockHandler = xorgBlockHandler;
+
+    ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    {
+       RegionPtr dirty = DamageRegion(ms->damage);
+       unsigned num_cliprects = REGION_NUM_RECTS(dirty);
+
+       if (num_cliprects) {
+           drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
+           BoxPtr rect = REGION_RECTS(dirty);
+           int i;
+
+           for (i = 0; i < num_cliprects; i++, rect++) {
+               clip[i].x = rect->x1;
+               clip[i].y = rect->y1;
+               clip[i].width = rect->x2 - rect->x1;
+               clip[i].height = rect->y2 - rect->y1;
+           }
+
+           /* TODO query connector property to see if this is needed */
+           drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
+
+           DamageEmpty(ms->damage);
+       }
+    }
+#endif
+}
+
 static Bool
 CreateScreenResources(ScreenPtr pScreen)
 {
@@ -460,6 +499,21 @@ CreateScreenResources(ScreenPtr pScreen)
 
     AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
+                              pScreen, rootPixmap);
+
+    if (ms->damage) {
+       DamageRegister(&rootPixmap->drawable, ms->damage);
+
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
+    } else {
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                  "Failed to create screen damage record\n");
+       return FALSE;
+    }
+#endif
+
     return ret;
 }
 
@@ -536,6 +590,8 @@ ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 
     fbPictureInit(pScreen, NULL, 0);
 
+    ms->blockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = xorgBlockHandler;
     ms->createScreenResources = pScreen->CreateScreenResources;
     pScreen->CreateScreenResources = CreateScreenResources;
 
@@ -699,8 +755,17 @@ CloseScreen(int scrnIndex, ScreenPtr pScreen)
     driCloseScreen(pScreen);
 #endif
 
+    pScreen->BlockHandler = ms->blockHandler;
     pScreen->CreateScreenResources = ms->createScreenResources;
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    if (ms->damage) {
+       DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
+       DamageDestroy(ms->damage);
+       ms->damage = NULL;
+    }
+#endif
+
     if (ms->exa)
        xorg_exa_close(pScrn);
 
index 9f3f82c..3c90c2c 100644 (file)
@@ -472,7 +472,11 @@ ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
        pipe_texture_reference(&priv->tex, NULL);
     }
 
-    if (!priv->tex) {
+    if (!priv->tex
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+       && priv->flags
+#endif
+       ) {
        struct pipe_texture template;
 
        memset(&template, 0, sizeof(template));
@@ -488,6 +492,14 @@ ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
        priv->tex = exa->scrn->texture_create(exa->scrn, &template);
     }
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    if (!priv->tex) {
+       if (pPixData)
+           pPixmap->devPrivate.ptr = pPixData;
+       else
+           pPixmap->devPrivate.ptr = xalloc(pPixmap->drawable.height * pPixmap->devKind);
+    } else
+#endif
     if (pPixData) {
        struct pipe_transfer *transfer =
            exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0,
index 910782d..da850bb 100644 (file)
 #include <xf86.h>
 #include <exa.h>
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+#include <damage.h>
+#endif
+
 #include "pipe/p_screen.h"
 #include "state_tracker/drm_api.h"
 
@@ -76,6 +80,7 @@ typedef struct _modesettingRec
 
     unsigned int SaveGeneration;
 
+    void (*blockHandler)(int, pointer, pointer, pointer);
     CreateScreenResourcesProcPtr createScreenResources;
 
     /* gallium */
@@ -87,6 +92,9 @@ typedef struct _modesettingRec
     void *exa;
     Bool noEvict;
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    DamagePtr damage;
+#endif
 } modesettingRec, *modesettingPtr;
 
 #define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate))