diff options
author | Jon Turney <jon.turney@dronecode.org.uk> | 2015-11-07 19:44:09 +0000 |
---|---|---|
committer | Jon Turney <jon.turney@dronecode.org.uk> | 2018-05-13 18:21:59 +0100 |
commit | 0d9eac9faa2c8a28994a75fe26b2ed4bd20c75db (patch) | |
tree | 934780ba6a4a364b1c1c81c8b19ce8e7a70e8042 | |
parent | 4e21719315cefcf8e4eeef008044662228a49328 (diff) |
Improve performance of -compositewm
I think that the major cost in the current implementation is doing a
CreateDIBSection()/DestroyObject() on every refresh. So provide our own
CreatePixmap() instead, which does the CreateDIBSection(), once.
Testcase: glxgears or foobillard with direct swrast
Testcase: scrolling in a full-screen xterm
v2:
Fix handling of RENDER Scratch Pixmaps
(A problem easily shown with gitk or emacs)
-rw-r--r-- | hw/xwin/win.h | 18 | ||||
-rw-r--r-- | hw/xwin/winmultiwindowwindow.c | 254 | ||||
-rw-r--r-- | hw/xwin/winscrinit.c | 17 | ||||
-rw-r--r-- | hw/xwin/winshadgdi.c | 43 |
4 files changed, 290 insertions, 42 deletions
diff --git a/hw/xwin/win.h b/hw/xwin/win.h index f775c3553..9790cbe7e 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -297,10 +297,8 @@ typedef Bool (*winCreateScreenResourcesProc) (ScreenPtr); */ typedef struct { - HDC hdcSelected; HBITMAP hBitmap; - BYTE *pbBits; - DWORD dwScanlineBytes; + void *pbBits; BITMAPINFOHEADER *pbmih; } winPrivPixmapRec, *winPrivPixmapPtr; @@ -516,6 +514,7 @@ typedef struct _winPrivScreenRec { ResizeWindowProcPtr ResizeWindow; MoveWindowProcPtr MoveWindow; SetShapeProcPtr SetShape; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; winCursorRec cursor; @@ -927,6 +926,19 @@ void winCopyWindowMultiWindow(WindowPtr pWin, DDXPointRec oldpt, RegionPtr oldRegion); +PixmapPtr +winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint); +Bool +winDestroyPixmapMultiwindow(PixmapPtr pPixmap); + +Bool +winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, int devKind, void *pPixData); + XID winGetWindowID(WindowPtr pWin); diff --git a/hw/xwin/winmultiwindowwindow.c b/hw/xwin/winmultiwindowwindow.c index 0f65bd93a..c2d144447 100644 --- a/hw/xwin/winmultiwindowwindow.c +++ b/hw/xwin/winmultiwindowwindow.c @@ -1172,3 +1172,257 @@ winAdjustXWindow(WindowPtr pWin, HWND hwnd) #undef WIDTH #undef HEIGHT } + +/* + Helper function + */ +static HBITMAP winCreateDIB(ScreenPtr pScreen, int width, int height, int bpp, void **ppvBits, BITMAPINFOHEADER **ppbmih) +{ + winScreenPriv(pScreen); + BITMAPV4HEADER *pbmih = NULL; + HBITMAP hBitmap = NULL; + + /* Allocate bitmap info header */ + pbmih = malloc(sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD)); + if (pbmih == NULL) { + ErrorF("winCreateDIB: malloc() failed\n"); + return NULL; + } + memset(pbmih, 0, sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD)); + + /* Describe bitmap to be created */ + pbmih->bV4Size = sizeof(BITMAPV4HEADER); + pbmih->bV4Width = width; + pbmih->bV4Height = -height; /* top-down bitmap */ + pbmih->bV4Planes = 1; + pbmih->bV4BitCount = bpp; + if (bpp == 1) { + RGBQUAD *bmiColors = (RGBQUAD *)((char *)pbmih + sizeof(BITMAPV4HEADER)); + pbmih->bV4V4Compression = BI_RGB; + bmiColors[1].rgbBlue = 255; + bmiColors[1].rgbGreen = 255; + bmiColors[1].rgbRed = 255; + } + else if (bpp == 8) { + pbmih->bV4V4Compression = BI_RGB; + pbmih->bV4ClrUsed = 0; + } + else if (bpp == 16) { + pbmih->bV4V4Compression = BI_RGB; + pbmih->bV4ClrUsed = 0; + } + else if (bpp == 32) { + pbmih->bV4V4Compression = BI_BITFIELDS; + pbmih->bV4RedMask = pScreenPriv->dwRedMask; + pbmih->bV4GreenMask = pScreenPriv->dwGreenMask; + pbmih->bV4BlueMask = pScreenPriv->dwBlueMask; + pbmih->bV4AlphaMask = 0; + } + else { + ErrorF("winCreateDIB: %d bpp unhandled\n", bpp); + } + + /* Create a DIB with a bit pointer */ + hBitmap = CreateDIBSection(NULL, + (BITMAPINFO *) pbmih, + DIB_RGB_COLORS, ppvBits, NULL, 0); + if (hBitmap == NULL) { + ErrorF("winCreateDIB: CreateDIBSection() failed\n"); + return NULL; + } + + /* Store the address of the BMIH in the ppbmih parameter */ + *ppbmih = (BITMAPINFOHEADER *)pbmih; + + winDebug("winCreateDIB: HBITMAP %p pBMIH %p pBits %p\n", hBitmap, pbmih, *ppvBits); + + return hBitmap; +} + + +/* + * CreatePixmap - See Porting Layer Definition + */ +PixmapPtr +winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + winPrivPixmapPtr pPixmapPriv = NULL; + PixmapPtr pPixmap = NULL; + int bpp, paddedwidth; + + /* allocate Pixmap header and privates */ + pPixmap = AllocatePixmap(pScreen, 0); + if (!pPixmap) + return NullPixmap; + + bpp = BitsPerPixel(depth); + /* + DIBs have 4-byte aligned rows + + paddedwidth is the width in bytes, padded to align + + i.e. round up the number of bits used by a row so it is a multiple of 32, + then convert to bytes + */ + paddedwidth = (((bpp * width) + 31) & ~31)/8; + + /* setup Pixmap header */ + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bpp; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = paddedwidth; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = NULL; // later set to pbBits + pPixmap->master_pixmap = NULL; +#ifdef COMPOSITE + pPixmap->screen_x = 0; + pPixmap->screen_y = 0; +#endif + pPixmap->usage_hint = usage_hint; + + /* Check for zero width or height pixmaps */ + if (width == 0 || height == 0) { + /* DIBs with a dimension of 0 aren't permitted, so don't try to allocate + a DIB, just set fields and return */ + return pPixmap; + } + + /* Initialize pixmap privates */ + pPixmapPriv = winGetPixmapPriv(pPixmap); + pPixmapPriv->hBitmap = NULL; + pPixmapPriv->pbBits = NULL; + pPixmapPriv->pbmih = NULL; + + /* Create a DIB for the pixmap */ + pPixmapPriv->hBitmap = winCreateDIB(pScreen, width, height, bpp, &pPixmapPriv->pbBits, &pPixmapPriv->pbmih); + + winDebug("winCreatePixmap: pPixmap %p HBITMAP %p pBMIH %p pBits %p\n", pPixmap, pPixmapPriv->hBitmap, pPixmapPriv->pbmih, pPixmapPriv->pbBits); + /* XXX: so why do we need this in privates ??? */ + pPixmap->devPrivate.ptr = pPixmapPriv->pbBits; + + return pPixmap; +} + +/* + * DestroyPixmap - See Porting Layer Definition + */ +Bool +winDestroyPixmapMultiwindow(PixmapPtr pPixmap) +{ + winPrivPixmapPtr pPixmapPriv = NULL; + + /* Bail early if there is not a pixmap to destroy */ + if (pPixmap == NULL) { + return TRUE; + } + + /* Decrement reference count, return if nonzero */ + --pPixmap->refcnt; + if (pPixmap->refcnt != 0) + return TRUE; + + winDebug("winDestroyPixmap: pPixmap %p\n", pPixmap); + + /* Get a handle to the pixmap privates */ + pPixmapPriv = winGetPixmapPriv(pPixmap); + + /* Free GDI bitmap */ + if (pPixmapPriv->hBitmap) + DeleteObject(pPixmapPriv->hBitmap); + + /* Free the bitmap info header memory */ + free(pPixmapPriv->pbmih); + pPixmapPriv->pbmih = NULL; + + /* Free the pixmap memory */ + free(pPixmap); + pPixmap = NULL; + + return TRUE; +} + +/* + * ModifyPixmapHeader - See Porting Layer Definition + */ +Bool +winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, int devKind, void *pPixData) +{ + int i; + winPrivPixmapPtr pPixmapPriv = NULL; + Bool fResult; + + /* reinitialize everything */ + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + pPixmap->drawable.id = 0; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = devKind; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = pPixData; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + /* + This can be used for some out-of-order initialization on the screen + pixmap, which is the only case we can properly support. + */ + + /* Look for which screen this pixmap corresponds to */ + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + if (pScreenInfo->pfb == pPixData) + { + /* and initialize pixmap privates from screen privates */ + pPixmapPriv = winGetPixmapPriv(pPixmap); + + pPixmapPriv->hBitmap = pScreenPriv->hbmpShadow; + pPixmapPriv->pbBits = pScreenInfo->pfb; + pPixmapPriv->pbmih = pScreenPriv->pbmih; + + /* XXX: need to mark these not to get released in DestroyPixmap */ + + return TRUE; + } + } + + /* Otherwise, since creating a DIBSection from arbitrary memory is not + * possible, fallback to normal. Later we can create a DIBSection with a + * copy of the bits, if needed. */ + { + pPixmapPriv = winGetPixmapPriv(pPixmap); + + pPixmapPriv->hBitmap = 0; + pPixmapPriv->pbBits = 0; + pPixmapPriv->pbmih = 0; + } + + winDebug("winModifyPixmapHeaderMultiwindow: falling back\n"); + + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + winScreenPriv(pScreen); + WIN_UNWRAP(ModifyPixmapHeader); + fResult = (*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData); + WIN_WRAP(ModifyPixmapHeader, winModifyPixmapHeaderMultiwindow); + } + + return fResult; +} diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c index f761e2337..33dcf70ac 100644 --- a/hw/xwin/winscrinit.c +++ b/hw/xwin/winscrinit.c @@ -269,6 +269,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) return FALSE; } + if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { + ErrorF("-compositewm disabled due to 8bpp depth\n"); + pScreenInfo->fCompositeWM = FALSE; + } + /* Apparently we need this for the render extension */ miSetPixmapDepths(); @@ -431,6 +436,7 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) WRAP(MoveWindow); WRAP(CopyWindow); WRAP(SetShape); + WRAP(ModifyPixmapHeader); /* Assign multi-window window procedures to be top level procedures */ pScreen->CreateWindow = winCreateWindowMultiWindow; @@ -446,6 +452,12 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) pScreen->CopyWindow = winCopyWindowMultiWindow; pScreen->SetShape = winSetShapeMultiWindow; + if (pScreenInfo->fCompositeWM) { + pScreen->CreatePixmap = winCreatePixmapMultiwindow; + pScreen->DestroyPixmap = winDestroyPixmapMultiwindow; + pScreen->ModifyPixmapHeader = winModifyPixmapHeaderMultiwindow; + } + /* Undefine the WRAP macro, as it is not needed elsewhere */ #undef WRAP } @@ -475,11 +487,6 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) if (pScreenInfo->fMultiWindow) { - if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { - ErrorF("-compositewm disabled due to 8bpp depth\n"); - pScreenInfo->fCompositeWM = FALSE; - } - #if CYGDEBUG || YES winDebug("winFinishScreenInitFB - Calling winInitWM.\n"); #endif diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index f767a1d59..ab602ba04 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -831,41 +831,17 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) HBITMAP hBitmap; HDC hdcPixmap; PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); + winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap); - /* - This is kind of clunky, and possibly not very efficient. - - Would it be more efficient to only create the DIB bitmap when the - composite bitmap is realloced and store it in a window private? - - But we still end up copying and converting all the bits from the - window pixmap into a DDB for every update. - - Perhaps better still would be to wrap the screen CreatePixmap routine - so it uses CreateDIBSection()? - */ - - BITMAPV4HEADER bmih; - memset(&bmih, 0, sizeof(bmih)); - bmih.bV4Size = sizeof(BITMAPV4HEADER); - bmih.bV4Width = pPixmap->drawable.width; - bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */ - bmih.bV4Planes = 1; - bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel; - bmih.bV4SizeImage = 0; /* window pixmap format is the same as the screen pixmap */ assert(pPixmap->drawable.bitsPerPixel > 8); - bmih.bV4V4Compression = BI_BITFIELDS; - bmih.bV4RedMask = pScreenPriv->dwRedMask; - bmih.bV4GreenMask = pScreenPriv->dwGreenMask; - bmih.bV4BlueMask = pScreenPriv->dwBlueMask; - bmih.bV4AlphaMask = 0; - - /* Create the window bitmap from the pixmap */ - hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen, - (BITMAPINFOHEADER *)&bmih, CBM_INIT, - pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih, - DIB_RGB_COLORS); + + /* Get the window bitmap from the pixmap */ + hBitmap = pPixmapPriv->hBitmap; + + /* XXX: There may be a need for a slow-path here: If hBitmap is NULL, we + should fall-back to creating a Windows DIB from the pixmap, then + deleting it after the BitBlt. */ /* Select the window bitmap into a screen-compatible DC */ hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen); @@ -883,9 +859,8 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n", (unsigned int)GetLastError()); - /* Release */ + /* Release DC */ DeleteDC(hdcPixmap); - DeleteObject(hBitmap); } else #endif |