summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Turney <jon.turney@dronecode.org.uk>2015-11-07 19:44:09 +0000
committerJon Turney <jon.turney@dronecode.org.uk>2018-05-13 18:21:59 +0100
commit0d9eac9faa2c8a28994a75fe26b2ed4bd20c75db (patch)
tree934780ba6a4a364b1c1c81c8b19ce8e7a70e8042
parent4e21719315cefcf8e4eeef008044662228a49328 (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.h18
-rw-r--r--hw/xwin/winmultiwindowwindow.c254
-rw-r--r--hw/xwin/winscrinit.c17
-rw-r--r--hw/xwin/winshadgdi.c43
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