From 46ac5c2c39a476c44fae207ca9745a8a60c7ea72 Mon Sep 17 00:00:00 2001
From: Fedora X Ninjas <x@fedoraproject.org>
Date: Wed, 19 Aug 2015 13:45:43 -0400
Subject: [PATCH] kms: implement a double-buffered shadow mode
Signed-off-by: Fedora X Ninjas <x@fedoraproject.org>
---
hw/xfree86/drivers/modesetting/driver.c | 127 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.c | 7 ++
hw/xfree86/drivers/modesetting/drmmode_display.h | 2 +
3 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 1215cb3..b0c2f17 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -124,6 +124,7 @@ typedef enum {
OPTION_DEVICE_PATH,
OPTION_SHADOW_FB,
OPTION_ACCEL_METHOD,
+ OPTION_DOUBLE_SHADOW,
} modesettingOpts;
static const OptionInfoRec Options[] = {
@@ -131,6 +132,7 @@ static const OptionInfoRec Options[] = {
{OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE},
{OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
+ {OPTION_DOUBLE_SHADOW, "DoubleShadow", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
@@ -615,6 +617,32 @@ try_enable_glamor(ScrnInfoPtr pScrn)
#endif
}
+static Bool
+msShouldDoubleShadow(ScrnInfoPtr pScrn, modesettingPtr ms)
+{
+ Bool ret = FALSE, asked;
+ int from;
+ drmVersionPtr v = drmGetVersion(ms->fd);
+
+ if (!strcmp(v->name, "mgag200") ||
+ !strcmp(v->name, "ast")) /* XXX || rn50 */
+ ret = TRUE;
+
+ drmFreeVersion(v);
+
+ asked = xf86GetOptValBool(ms->Options, OPTION_DOUBLE_SHADOW, &ret);
+
+ if (asked)
+ from = X_CONFIG;
+ else
+ from = X_INFO;
+
+ xf86DrvMsg(pScrn->scrnIndex, from,
+ "Double-buffered shadow updates: %s", ret ? "on" : "off");
+
+ return ret;
+}
+
#ifndef DRM_CAP_CURSOR_WIDTH
#define DRM_CAP_CURSOR_WIDTH 0x8
#endif
@@ -814,6 +842,8 @@ PreInit(ScrnInfoPtr pScrn, int flags)
prefer_shadow ? "YES" : "NO",
ms->drmmode.force_24_32 ? "FORCE" :
ms->drmmode.shadow_enable ? "YES" : "NO");
+
+ ms->drmmode.shadow_enable2 = msShouldDoubleShadow(pScrn, ms);
}
if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
@@ -872,10 +902,91 @@ msShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode,
return ((uint8_t *) ms->drmmode.front_bo.dumb->ptr + row * stride + offset);
}
+/* somewhat arbitrary tile size, in pixels */
+#define TILE 16
+
+static int
+msUpdateIntersect(modesettingPtr ms, shadowBufPtr pBuf, BoxPtr box,
+ xRectangle *prect)
+{
+ int i, dirty = 0, stride = pBuf->pPixmap->devKind, cpp = ms->drmmode.cpp;
+ int width = (box->x2 - box->x1) * cpp;
+ unsigned char *old, *new;
+
+ old = ms->drmmode.shadow_fb2;
+ old += (box->y1 * stride) + (box->x1 * cpp);
+ new = ms->drmmode.shadow_fb;
+ new += (box->y1 * stride) + (box->x1 * cpp);
+
+ for (i = box->y2 - box->y1 - 1; i >= 0; i--) {
+ unsigned char *o = old + i * stride,
+ *n = new + i * stride;
+ if (memcmp(o, n, width) != 0) {
+ dirty = 1;
+ memcpy(o, n, width);
+ }
+ }
+
+ if (dirty) {
+ prect->x = box->x1;
+ prect->y = box->y1;
+ prect->width = box->x2 - box->x1;
+ prect->height = box->y2 - box->y1;
+ }
+
+ return dirty;
+}
+
static void
msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
{
- shadowUpdatePacked(pScreen, pBuf);
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+ modesettingPtr ms = modesettingPTR(pScrn);
+ Bool use_ms_shadow = ms->drmmode.force_24_32 && pScrn->bitsPerPixel == 32;
+
+ if (ms->drmmode.shadow_enable2 && ms->drmmode.shadow_fb2) do {
+ RegionPtr damage = DamageRegion(pBuf->pDamage), tiles;
+ BoxPtr extents = RegionExtents(damage);
+ xRectangle *prect;
+ int nrects;
+ int i, j, tx1, tx2, ty1, ty2;
+
+ tx1 = extents->x1 / TILE;
+ tx2 = (extents->x2 + TILE - 1) / TILE;
+ ty1 = extents->y1 / TILE;
+ ty2 = (extents->y2 + TILE - 1) / TILE;
+
+ nrects = (tx2 - tx1) * (ty2 - ty1);
+ if (!(prect = calloc(nrects, sizeof(xRectangle))))
+ break;
+
+ nrects = 0;
+ for (j = ty2 - 1; j >= ty1; j--) {
+ for (i = tx2 - 1; i >= tx1; i--) {
+ BoxRec box;
+
+ box.x1 = max(i * TILE, extents->x1);
+ box.y1 = max(j * TILE, extents->y1);
+ box.x2 = min((i+1) * TILE, extents->x2);
+ box.y2 = min((j+1) * TILE, extents->y2);
+
+ if (RegionContainsRect(damage, &box) != rgnOUT) {
+ if (msUpdateIntersect(ms, pBuf, &box, prect + nrects)) {
+ nrects++;
+ }
+ }
+ }
+ }
+
+ tiles = RegionFromRects(nrects, prect, CT_NONE);
+ RegionIntersect(damage, damage, tiles);
+ RegionDestroy(tiles);
+ } while (0);
+
+ if (use_ms_shadow)
+ ms_shadowUpdate32to24(pScreen, pBuf);
+ else
+ shadowUpdatePacked(pScreen, pBuf);
}
static Bool
@@ -887,7 +998,6 @@ CreateScreenResources(ScreenPtr pScreen)
Bool ret;
void *pixels = NULL;
int err;
- Bool use_ms_shadow = ms->drmmode.force_24_32 && pScrn->bitsPerPixel == 32;
pScreen->CreateScreenResources = ms->createScreenResources;
ret = pScreen->CreateScreenResources(pScreen);
@@ -915,13 +1025,18 @@ CreateScreenResources(ScreenPtr pScreen)
if (ms->drmmode.shadow_enable)
pixels = ms->drmmode.shadow_fb;
+ if (ms->drmmode.shadow_enable2) {
+ ms->drmmode.shadow_fb2 = calloc(1, pScrn->displayWidth * pScrn->virtualY * ((pScrn->bitsPerPixel + 7) >> 3));
+ if (!ms->drmmode.shadow_fb2)
+ ms->drmmode.shadow_enable2 = FALSE;
+ }
+
if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, pixels))
FatalError("Couldn't adjust screen pixmap\n");
if (ms->drmmode.shadow_enable) {
- if (!shadowAdd(pScreen, rootPixmap,
- use_ms_shadow ? ms_shadowUpdate32to24 : msUpdatePacked,
- msShadowWindow, 0, 0))
+ if (!shadowAdd(pScreen, rootPixmap, msUpdatePacked, msShadowWindow,
+ 0, 0))
return FALSE;
}
@@ -1238,6 +1353,8 @@ CloseScreen(ScreenPtr pScreen)
shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
free(ms->drmmode.shadow_fb);
ms->drmmode.shadow_fb = NULL;
+ free(ms->drmmode.shadow_fb2);
+ ms->drmmode.shadow_fb2 = NULL;
}
drmmode_uevent_fini(pScrn, &ms->drmmode);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 079fceb..66f0bbe 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -1382,6 +1382,13 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
drmmode->shadow_fb = new_pixels;
}
+ if (drmmode->shadow_enable2) {
+ uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
+ void *fb2 = calloc(1, size);
+ free(drmmode->shadow_fb2);
+ drmmode->shadow_fb2 = fb2;
+ }
+
screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
scrn->displayWidth * cpp, new_pixels);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 927efec..3a7d222 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -65,8 +65,10 @@ typedef struct {
Bool glamor;
Bool shadow_enable;
+ Bool shadow_enable2;
Bool force_24_32;
void *shadow_fb;
+ void *shadow_fb2;
/**
* A screen-sized pixmap when we're doing triple-buffered DRI2
--
2.5.0