Use GDI Batch for PatBlt

This should increase speed a bit. Makes a good argument to use
PolyPatBlt for more than one call.
PolyPatBlt is not fully tested yet.
This commit is contained in:
jimtabor 2019-03-02 11:30:21 -06:00
parent 1114b89952
commit b6262a25fd
3 changed files with 218 additions and 5 deletions

View File

@ -388,8 +388,8 @@ GdiAllocBatchCommand(
}
/* Get the size of the entry */
if (Cmd == GdiBCPatBlt) cjSize = 0;
else if (Cmd == GdiBCPolyPatBlt) cjSize = 0;
if (Cmd == GdiBCPatBlt) cjSize = sizeof(GDIBSPATBLT);
else if (Cmd == GdiBCPolyPatBlt) cjSize = sizeof(GDIBSPPATBLT);
else if (Cmd == GdiBCTextOut) cjSize = 0;
else if (Cmd == GdiBCExtTextOut) cjSize = 0;
else if (Cmd == GdiBCSetBrushOrg) cjSize = sizeof(GDIBSSETBRHORG);

View File

@ -456,9 +456,35 @@ PatBlt(
_In_ INT nHeight,
_In_ DWORD dwRop)
{
PDC_ATTR pdcattr;
HANDLE_METADC(BOOL, PatBlt, FALSE, hdc, nXLeft, nYLeft, nWidth, nHeight, dwRop);
/* FIXME some part need be done in user mode */
/* Get the DC attribute */
pdcattr = GdiGetDcAttr(hdc);
if (pdcattr && !(pdcattr->ulDirty_ & DC_DIBSECTION))
{
PGDIBSPATBLT pgO;
pgO = GdiAllocBatchCommand(hdc, GdiBCPatBlt);
if (pgO)
{
pgO->nXLeft = nXLeft;
pgO->nYLeft = nYLeft;
pgO->nWidth = nWidth;
pgO->nHeight = nHeight;
pgO->dwRop = dwRop;
/* Snapshot attributes */
pgO->hbrush = pdcattr->hbrush;
pgO->crForegroundClr = pdcattr->crForegroundClr;
pgO->crBackgroundClr = pdcattr->crBackgroundClr;
pgO->crBrushClr = pdcattr->crBrushClr;
pgO->ulForegroundClr = pdcattr->ulForegroundClr;
pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
pgO->ulBrushClr = pdcattr->ulBrushClr;
return TRUE;
}
}
return NtGdiPatBlt( hdc, nXLeft, nYLeft, nWidth, nHeight, dwRop);
}
@ -474,6 +500,7 @@ PolyPatBlt(
UINT i;
BOOL bResult;
HBRUSH hbrOld;
PDC_ATTR pdcattr;
/* Handle meta DCs */
if ((GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) ||
@ -511,7 +538,37 @@ PolyPatBlt(
return bResult;
}
/* FIXME some part need be done in user mode */
/* Get the DC attribute */
pdcattr = GdiGetDcAttr(hdc);
if (nCount && pdcattr && !(pdcattr->ulDirty_ & DC_DIBSECTION))
{
PGDIBSPPATBLT pgO;
PTEB pTeb = NtCurrentTeb();
pgO = GdiAllocBatchCommand(hdc, GdiBCPolyPatBlt);
if (pgO)
{
USHORT cjSize = sizeof(GDIBSPPATBLT) + (nCount-1) * sizeof(PATRECT);
if ((pTeb->GdiTebBatch.Offset + cjSize) <= GDIBATCHBUFSIZE)
{
pgO->Count = nCount;
pgO->Mode = dwMode;
pgO->rop4 = dwRop;
/* Snapshot attributes */
pgO->crForegroundClr = pdcattr->crForegroundClr;
pgO->crBackgroundClr = pdcattr->crBackgroundClr;
pgO->crBrushClr = pdcattr->crBrushClr;
pgO->ulForegroundClr = pdcattr->ulForegroundClr;
pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
pgO->ulBrushClr = pdcattr->ulBrushClr;
RtlCopyMemory(pgO->pRect, pPoly, nCount * sizeof(PATRECT));
// Recompute offset, remember one is already accounted for in the structure.
pTeb->GdiTebBatch.Offset += (nCount-1) * sizeof(PATRECT);
return TRUE;
}
}
}
return NtGdiPolyPatBlt(hdc, dwRop, pPoly, nCount, dwMode);
}

View File

@ -4,6 +4,7 @@
#define NDEBUG
#include <debug.h>
BOOL FASTCALL IntPatBlt( PDC,INT,INT,INT,INT,DWORD,PEBRUSHOBJ);
//
// Gdi Batch Flush support functions.
@ -89,16 +90,171 @@ GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
switch(Cmd)
{
case GdiBCPatBlt:
{
PGDIBSPATBLT pgDPB;
DWORD dwRop, flags;
HBRUSH hOrgBrush;
COLORREF crColor, crBkColor, crBrushClr;
ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
if (!dc) break;
pgDPB = (PGDIBSPATBLT) pHdr;
/* Convert the ROP3 to a ROP4 */
dwRop = pgDPB->dwRop;
dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
/* Check if the rop uses a source */
if (WIN32_ROP4_USES_SOURCE(dwRop))
{
/* This is not possible */
break;
}
/* Check if the DC has no surface (empty mem or info DC) */
if (dc->dclevel.pSurface == NULL)
{
/* Nothing to do */
break;
}
// Save current attributes and flags
crColor = dc->pdcattr->crForegroundClr;
crBkColor = dc->pdcattr->ulBackgroundClr;
crBrushClr = dc->pdcattr->crBrushClr;
ulForegroundClr = dc->pdcattr->ulForegroundClr;
ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
ulBrushClr = dc->pdcattr->ulBrushClr;
hOrgBrush = dc->pdcattr->hbrush;
flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
// Set the attribute snapshot
dc->pdcattr->hbrush = pgDPB->hbrush;
dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
// Process dirty attributes if any
if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
DC_vUpdateFillBrush(dc);
if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
DC_vUpdateTextBrush(dc);
if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
DC_vUpdateBackgroundBrush(dc);
/* Call the internal function */
IntPatBlt(dc, pgDPB->nXLeft, pgDPB->nYLeft, pgDPB->nWidth, pgDPB->nHeight, dwRop, &dc->eboFill);
// Restore attributes and flags
dc->pdcattr->hbrush = hOrgBrush;
dc->pdcattr->crForegroundClr = crColor;
dc->pdcattr->crBackgroundClr = crBkColor;
dc->pdcattr->crBrushClr = crBrushClr;
dc->pdcattr->ulForegroundClr = ulForegroundClr;
dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
dc->pdcattr->ulBrushClr = ulBrushClr;
dc->pdcattr->ulDirty_ |= flags;
break;
}
case GdiBCPolyPatBlt:
break;
{
PGDIBSPPATBLT pgDPB;
EBRUSHOBJ eboFill;
PBRUSH pbrush;
PPATRECT pRects;
INT cRects, i;
DWORD dwRop, flags;
COLORREF crColor, crBkColor, crBrushClr;
ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
if (!dc) break;
pgDPB = (PGDIBSPPATBLT) pHdr;
/* Convert the ROP3 to a ROP4 */
dwRop = pgDPB->rop4;
dwRop = MAKEROP4(dwRop & 0xFF0000, dwRop);
/* Check if the rop uses a source */
if (WIN32_ROP4_USES_SOURCE(dwRop))
{
/* This is not possible */
break;
}
/* Check if the DC has no surface (empty mem or info DC) */
if (dc->dclevel.pSurface == NULL)
{
/* Nothing to do */
break;
}
// Save current attributes and flags
crColor = dc->pdcattr->crForegroundClr;
crBkColor = dc->pdcattr->ulBackgroundClr;
crBrushClr = dc->pdcattr->crBrushClr;
ulForegroundClr = dc->pdcattr->ulForegroundClr;
ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
ulBrushClr = dc->pdcattr->ulBrushClr;
flags = dc->pdcattr->ulDirty_ & (DIRTY_BACKGROUND | DIRTY_TEXT | DIRTY_FILL | DC_BRUSH_DIRTY);
// Set the attribute snapshot
dc->pdcattr->crForegroundClr = pgDPB->crForegroundClr;
dc->pdcattr->crBackgroundClr = pgDPB->crBackgroundClr;
dc->pdcattr->crBrushClr = pgDPB->crBrushClr;
dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
// Process dirty attributes if any
if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
DC_vUpdateTextBrush(dc);
if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
DC_vUpdateBackgroundBrush(dc);
DPRINT1("GdiBCPolyPatBlt Testing\n");
pRects = pgDPB->pRect;
cRects = pgDPB->Count;
for (i = 0; i < cRects; i++)
{
pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
/* Check if we could lock the brush */
if (pbrush != NULL)
{
/* Initialize a brush object */
EBRUSHOBJ_vInitFromDC(&eboFill, pbrush, dc);
IntPatBlt(
dc,
pRects->r.left,
pRects->r.top,
pRects->r.right,
pRects->r.bottom,
dwRop,
&eboFill);
/* Cleanup the brush object and unlock the brush */
EBRUSHOBJ_vCleanup(&eboFill);
BRUSH_ShareUnlockBrush(pbrush);
}
pRects++;
}
// Restore attributes and flags
dc->pdcattr->crForegroundClr = crColor;
dc->pdcattr->crBackgroundClr = crBkColor;
dc->pdcattr->crBrushClr = crBrushClr;
dc->pdcattr->ulForegroundClr = ulForegroundClr;
dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
dc->pdcattr->ulBrushClr = ulBrushClr;
dc->pdcattr->ulDirty_ |= flags;
break;
}
case GdiBCTextOut:
break;
case GdiBCExtTextOut:
{
//GreExtTextOutW( hDC,
// XStart,
// YStart,
// fuOptions,
// &SafeRect,
// SafeString,
// Count,
// SafeDx,
// dwCodePage );
break;
}
case GdiBCSetBrushOrg:
{