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 53d1a330951a84c68cc9fd5bf11f94ca58184e2b..923662b24a933ea7e843c62ce6001b069dc1fdbd 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 9f3f82c6c890113969e8e8ddc15249685672953a..3c90c2c9429fc453d25ed8a12bfef5196c8b7178 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 910782dbc4427aadf7bf2bf4ea5e464b36bf3808..da850bbf6498a95c848ba32e0d16927d07cd429d 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))