Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP4:GA
xf86-video-modesetting
u_02-modesetting-Implement-a-double-buffered-sh...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File u_02-modesetting-Implement-a-double-buffered-shadow-mode.patch of Package xf86-video-modesetting
From: Adam Jackson <ajax@redhat.com> Date: Wed Jul 22 12:14:08 2015 -0400 Subject: [PATCH 2/6]modesetting: Implement a double-buffered shadow mode Patch-mainline: to be upstreamed References: bsc#942871 Signed-off-by: Egbert Eich <eich@suse.com> Server GPUs often have a VNC feature attached to allow remote console. The controller implementing this feature is usually not very powerful, and we can easily swamp it with work. This is made somewhat worse by damage over-reporting the size of the dirty region, and a whole lot worse by applications (or shells) that update the screen with identical pixel content as was already there. Fix this by double-buffering the shadow fb, using memcmp to identify dirty tiles on each update pass. Since both shadows are in host memory the memcmp is cheap, and worth it given the win in network bandwidth. The tile size is somewhat arbitrarily chosen to be one cacheline wide at 32bpp on Intel Core. By default we enable this behaviour for (a subset of) known server GPUs; the heuristic could use work. Signed-off-by: Adam Jackson <ajax@redhat.com> --- src/driver.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++--- src/drmmode_display.c | 40 +++++++++------ src/drmmode_display.h | 2 + 3 files changed, 153 insertions(+), 21 deletions(-) diff --git a/src/driver.c b/src/driver.c index e5c472c..a88afa3 100644 --- a/src/driver.c +++ b/src/driver.c @@ -126,12 +126,14 @@ typedef enum OPTION_SW_CURSOR, OPTION_DEVICE_PATH, OPTION_SHADOW_FB, + OPTION_DOUBLE_SHADOW, } modesettingOpts; static const OptionInfoRec Options[] = { {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE }, {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DOUBLE_SHADOW, "DoubleShadow", OPTV_BOOLEAN, {0}, FALSE }, {-1, NULL, OPTV_NONE, {0}, FALSE} }; @@ -586,6 +588,32 @@ FreeRec(ScrnInfoPtr pScrn) } +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 @@ -771,6 +799,8 @@ PreInit(ScrnInfoPtr pScrn, int flags) 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) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n"); goto fail; @@ -827,10 +857,92 @@ msShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode, return ((uint8_t *)ms->drmmode.front_bo->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; + int cpp = ms->drmmode.scrn->bitsPerPixel >> 3; + 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.kbpp == 24 && 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; j >= ty1; j--) { + for (i = tx2; 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 @@ -841,7 +953,6 @@ CreateScreenResources(ScreenPtr pScreen) PixmapPtr rootPixmap; Bool ret; void *pixels; - Bool use_ms_shadow = ms->drmmode.kbpp == 24 && pScrn->bitsPerPixel == 32; pScreen->CreateScreenResources = ms->createScreenResources; ret = pScreen->CreateScreenResources(pScreen); @@ -862,14 +973,21 @@ 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; + else + pixels = ms->drmmode.shadow_fb2; + } + 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; } @@ -1130,6 +1248,8 @@ CloseScreen(CLOSE_SCREEN_ARGS_DECL) 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/src/drmmode_display.c b/src/drmmode_display.c index 30531a0..4de7cdc 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -1195,25 +1195,35 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) &drmmode->fb_id); if (ret) goto fail; - + new_pixels = drmmode_map_front_bo(drmmode); if (!new_pixels) goto fail; - if (!drmmode->shadow_enable) - screen->ModifyPixmapHeader(ppix, width, height, -1, -1, - pitch, new_pixels); - else { - void *new_shadow; - uint32_t size = scrn->displayWidth * scrn->virtualY * cpp; - new_shadow = calloc(1, size); - if (new_shadow == NULL) - goto fail; - free(drmmode->shadow_fb); - drmmode->shadow_fb = new_shadow; - screen->ModifyPixmapHeader(ppix, width, height, -1, -1, - scrn->displayWidth * cpp, drmmode->shadow_fb); - } + if (drmmode->shadow_enable) { + uint32_t size = scrn->displayWidth * scrn->virtualY * cpp; + new_pixels = calloc(1, size); + if (new_pixels == NULL) + goto fail; + free(drmmode->shadow_fb); + drmmode->shadow_fb = new_pixels; + } + + if (drmmode->shadow_enable2) { + uint32_t size = scrn->displayWidth * scrn->virtualY * cpp; + new_pixels = calloc(1, size); + free(drmmode->shadow_fb2); + if (new_pixels == NULL) { + /* fall back to single-shadow, retry next time we resize */ + new_pixels = drmmode->shadow_fb; + drmmode->shadow_fb2 = NULL; + } else { + drmmode->shadow_fb2 = new_pixels; + } + } + + screen->ModifyPixmapHeader(ppix, width, height, -1, -1, + pitch, new_pixels); #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0) scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; diff --git a/src/drmmode_display.h b/src/drmmode_display.h index e5d9be3..9096a2d 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -65,7 +65,9 @@ typedef struct { Bool sw_cursor; Bool shadow_enable; + Bool shadow_enable2; void *shadow_fb; + void *shadow_fb2; #ifdef HAVE_SCREEN_SPECIFIC_PRIVATE_KEYS DevPrivateKeyRec pixmapPrivateKeyRec;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor