From ce813f9c98d9074fe089ce9f74494abfe4dddce8 Mon Sep 17 00:00:00 2001 From: Fedora X Ninjas Date: Wed, 19 Aug 2015 13:45:43 -0400 Subject: [PATCH] kms: implement a double-buffered shadow mode v2: Free the rect list. Signed-off-by: Fedora X Ninjas --- hw/xfree86/drivers/modesetting/driver.c | 128 ++++++++++++++++++++++- hw/xfree86/drivers/modesetting/drmmode_display.c | 7 ++ hw/xfree86/drivers/modesetting/drmmode_display.h | 2 + 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 1215cb3..1189df7 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,92 @@ 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); + free(prect); + } while (0); + + if (use_ms_shadow) + ms_shadowUpdate32to24(pScreen, pBuf); + else + shadowUpdatePacked(pScreen, pBuf); } static Bool @@ -887,7 +999,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 +1026,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 +1354,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 349bddb..7dd85c8 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1393,6 +1393,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.7.0