/******************************Module*Header*******************************\ * Module Name: Brush.c * * Handles all brush/pattern initialization and realization. * * Copyright (c) 1992-1995 Microsoft Corporation * \**************************************************************************/ #include "precomp.h" /******************************Public*Routine******************************\ * VOID vRealizeDitherPattern * * Generates an 8x8 dither pattern, in our internal realization format, for * the colour ulRGBToDither. Note that the high byte of ulRGBToDither does * not need to be set to zero, because vComputeSubspaces ignores it. \**************************************************************************/ VOID vRealizeDitherPattern( RBRUSH* prb, ULONG ulRGBToDither) { ULONG ulNumVertices; VERTEX_DATA vVertexData[4]; VERTEX_DATA* pvVertexData; // Calculate what colour subspaces are involved in the dither: pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData); // Now that we have found the bounding vertices and the number of // pixels to dither for each vertex, we can create the dither pattern ulNumVertices = (ULONG)(pvVertexData - vVertexData); // # of vertices with more than zero pixels in the dither // Do the actual dithering: vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices); // Initialize the fields we need: prb->fl = 0; } /******************************Public*Routine******************************\ * BOOL DrvRealizeBrush * * This function allows us to convert GDI brushes into an internal form * we can use. It may be called directly by GDI at SelectObject time, or * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush * to create a realized brush in a function like DrvBitBlt. * * Note that we have no way of determining what the current Rop or brush * alignment are at this point. * \**************************************************************************/ BOOL DrvRealizeBrush( BRUSHOBJ* pbo, SURFOBJ* psoDst, SURFOBJ* psoPattern, SURFOBJ* psoMask, XLATEOBJ* pxlo, ULONG iHatch) { PDEV* ppdev; ULONG iPatternFormat; BYTE* pjSrc; BYTE* pjDst; LONG lSrcDelta; LONG cj; LONG i; LONG j; RBRUSH* prb; ULONG* pulXlate; ULONG* pulRBits; ppdev = (PDEV*) psoDst->dhpdev; // We don't do brushes in high-colour modes: if (ppdev->flStat & STAT_UNACCELERATED) goto ReturnFalse; // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE: if (iHatch & RB_DITHERCOLOR) { // Implementing DITHERONREALIZE increased our score on a certain // unmentionable benchmark by 0.4 million 'megapixels'. Too bad // this didn't work in the first version of NT. prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cjPel)); if (prb == NULL) goto ReturnFalse; vRealizeDitherPattern(prb, iHatch); goto ReturnTrue; } // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't // support patterns of any other size, it's a safe bet that 99.9% // of the patterns we'll ever get will be 8x8: if ((psoPattern->sizlBitmap.cx != 8) || (psoPattern->sizlBitmap.cy != 8)) goto ReturnFalse; // At 8bpp, we handle patterns at 1bpp and 8bpp with/without an xlate. iPatternFormat = psoPattern->iBitmapFormat; if ((iPatternFormat == BMF_1BPP) || (iPatternFormat == ppdev->iBitmapFormat)) { prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cjPel)); if (prb == NULL) goto ReturnFalse; // Initialize the fields we need: prb->fl = 0; lSrcDelta = psoPattern->lDelta; pjSrc = (BYTE*) psoPattern->pvScan0; pjDst = (BYTE*) &prb->aulPattern[0]; if (ppdev->iBitmapFormat == iPatternFormat) { if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) { DISPDBG((1, "Realizing un-translated brush")); // The pattern is the same colour depth as the screen, and // there's no translation to be done: cj = (8 * ppdev->cjPel); // Every pattern is 8 pels wide for (i = 8; i != 0; i--) { RtlCopyMemory(pjDst, pjSrc, cj); pjSrc += lSrcDelta; pjDst += cj; } } else if (ppdev->iBitmapFormat == BMF_8BPP) { DISPDBG((1, "Realizing 8bpp translated brush")); // The screen is 8bpp, and there's translation to be done: pulXlate = pxlo->pulXlate; for (i = 8; i != 0; i--) { for (j = 8; j != 0; j--) { *pjDst++ = (BYTE) pulXlate[*pjSrc++]; } pjSrc += lSrcDelta - 8; } } else { // I don't feel like writing code to handle translations // when our screen is 16bpp or higher (although I probably // should; we could allocate a temporary buffer and use // GDI to convert, like is done in the VGA driver). goto ReturnFalse; } } else { ASSERTDD(iPatternFormat == BMF_1BPP, "Expected 1bpp only"); for (i = 8; i != 0; i--) { *pjDst = *pjSrc; pjSrc += lSrcDelta; pjDst += 1; } pulXlate = pxlo->pulXlate; prb->fl = RBRUSH_2COLOR; prb->ulBackColor = pulXlate[0]; prb->ulForeColor = pulXlate[1]; } ReturnTrue: if (!(prb->fl & RBRUSH_2COLOR)) { pulRBits = (ULONG*) &prb->aulPattern[0]; prb->cy = 8; prb->cyLog2 = 3; prb->xBlockAlign = -1; // See if pattern is really only 4 scans long: ASSERTDD(ppdev->iBitmapFormat == BMF_8BPP, "This only works at 8bpp"); if (pulRBits[0] == pulRBits[8] && pulRBits[1] == pulRBits[9] && pulRBits[2] == pulRBits[10] && pulRBits[3] == pulRBits[11] && pulRBits[4] == pulRBits[12] && pulRBits[5] == pulRBits[13] && pulRBits[6] == pulRBits[14] && pulRBits[7] == pulRBits[15]) { prb->cy = 4; prb->cyLog2 = 2; // See if pattern is really only 2 scans long: if (pulRBits[0] == pulRBits[4] && pulRBits[1] == pulRBits[5] && pulRBits[2] == pulRBits[6] && pulRBits[3] == pulRBits[7]) { DISPDBG((2, "cy = 2 ")); prb->cy = 2; prb->cyLog2 = 1; } else { DISPDBG((2, "cy = 4 ")); } } else { DISPDBG((2, "cy = 8 ")); } // See if pattern is really only 4 pels wide: for (i = prb->cy / 2; i > 0; i--) { if (*(pulRBits ) != *(pulRBits + 1) || *(pulRBits + 2) != *(pulRBits + 3)) goto Not_4_Wide; pulRBits += 4; } DISPDBG((2, "4pels wide")); Not_4_Wide: ; } return(TRUE); } ReturnFalse: if (psoPattern != NULL) { DISPDBG((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li", psoPattern->iType, psoPattern->iBitmapFormat, psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy)); } return(FALSE); } /******************************Public*Routine******************************\ * VOID vAssertModeBrushCache * * Resets the brush cache when we exit out of full-screen. \**************************************************************************/ VOID vAssertModeBrushCache( PDEV* ppdev, BOOL bEnable) { } /******************************Public*Routine******************************\ * BOOL bEnableBrushCache * * Allocates off-screen memory for storing the brush cache. \**************************************************************************/ BOOL bEnableBrushCache( PDEV* ppdev) { return(TRUE); } /******************************Public*Routine******************************\ * VOID vDisableBrushCache * * Cleans up anything done in bEnableBrushCache. \**************************************************************************/ VOID vDisableBrushCache(PDEV* ppdev) { // We ain't gotta do nothin' }