Use GDI Batch for PatBlt
authorjimtabor <james.tabor@reactos.org>
Sat, 2 Mar 2019 17:30:21 +0000 (11:30 -0600)
committerjimtabor <james.tabor@reactos.org>
Sat, 2 Mar 2019 17:30:21 +0000 (11:30 -0600)
This should increase speed a bit. Makes a good argument to use
PolyPatBlt for more than one call.
PolyPatBlt is not fully tested yet.

win32ss/gdi/gdi32/include/gdi32p.h
win32ss/gdi/gdi32/objects/painting.c
win32ss/gdi/ntgdi/gdibatch.c

index 9dc2ec4..67d3a68 100644 (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);
index 150040c..efc987e 100644 (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);
 }
 
index bd9306a..3c7d6c2 100644 (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:
+     {
+        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:
      {