hw/xwin: Improve performance of -compositewm
I think that a 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) v3: Note that we don't own screen pixmap to release in DestroyPixmap Log if unimplemented slow-path ever gets hit
This commit is contained in:
parent
6865fe7147
commit
f67918353a
|
@ -296,11 +296,10 @@ typedef Bool (*winCreateScreenResourcesProc) (ScreenPtr);
|
|||
*/
|
||||
|
||||
typedef struct {
|
||||
HDC hdcSelected;
|
||||
HBITMAP hBitmap;
|
||||
BYTE *pbBits;
|
||||
DWORD dwScanlineBytes;
|
||||
void *pbBits;
|
||||
BITMAPINFOHEADER *pbmih;
|
||||
BOOL owned;
|
||||
} winPrivPixmapRec, *winPrivPixmapPtr;
|
||||
|
||||
/*
|
||||
|
@ -511,6 +510,7 @@ typedef struct _winPrivScreenRec {
|
|||
ResizeWindowProcPtr ResizeWindow;
|
||||
MoveWindowProcPtr MoveWindow;
|
||||
SetShapeProcPtr SetShape;
|
||||
ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
|
||||
|
||||
winCursorRec cursor;
|
||||
|
||||
|
@ -946,6 +946,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);
|
||||
|
||||
|
|
|
@ -960,3 +960,259 @@ winAdjustXWindow(WindowPtr pWin, HWND hwnd)
|
|||
#undef WIDTH
|
||||
#undef HEIGHT
|
||||
}
|
||||
|
||||
/*
|
||||
Helper function for creating a DIB to back a pixmap
|
||||
*/
|
||||
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);
|
||||
pPixmapPriv->owned = TRUE;
|
||||
|
||||
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);
|
||||
|
||||
/* Nothing to do if we don't own the DIB */
|
||||
if (!pPixmapPriv->owned)
|
||||
return TRUE;
|
||||
|
||||
/* 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 = winGetPixmapPriv(pPixmap);
|
||||
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->hBitmap = pScreenPriv->hbmpShadow;
|
||||
pPixmapPriv->pbBits = pScreenInfo->pfb;
|
||||
pPixmapPriv->pbmih = pScreenPriv->pbmih;
|
||||
|
||||
/* mark these not to get released by DestroyPixmap */
|
||||
pPixmapPriv->owned = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, since creating a DIBSection from arbitrary memory is not
|
||||
* possible, fallback to normal. If needed, we can create a DIBSection with
|
||||
* a copy of the bits later (see comment about a potential slow-path in
|
||||
* winBltExposedWindowRegionShadowGDI()). */
|
||||
pPixmapPriv->hBitmap = 0;
|
||||
pPixmapPriv->pbBits = 0;
|
||||
pPixmapPriv->pbmih = 0;
|
||||
pPixmapPriv->owned = FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -258,6 +258,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();
|
||||
|
||||
|
@ -417,6 +422,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;
|
||||
|
@ -432,6 +438,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
|
||||
}
|
||||
|
@ -461,11 +473,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
|
||||
|
|
|
@ -831,41 +831,22 @@ 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
|
||||
(because we couldn't back the pixmap with a Windows DIB), we should
|
||||
fall-back to creating a Windows DIB from the pixmap, then deleting it
|
||||
after the BitBlt (as this this code did before the fast-path was
|
||||
added). */
|
||||
if (!hBitmap) {
|
||||
ErrorF("winBltExposedWindowRegionShadowGDI - slow path unimplemented\n");
|
||||
}
|
||||
|
||||
/* Select the window bitmap into a screen-compatible DC */
|
||||
hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen);
|
||||
|
@ -883,9 +864,8 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
|
|||
ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n",
|
||||
GetLastError());
|
||||
|
||||
/* Release */
|
||||
/* Release DC */
|
||||
DeleteDC(hdcPixmap);
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user