|
|
/******************************Module*Header***********************************\
* * ******************* * * GDI SAMPLE CODE * * ******************* * * Module Name: stretch.c * * Contains all the stretch blt functions. * * Copyright (C) 1994-1998 3Dlabs Inc. Ltd. All rights reserved. * Copyright (C) 1995-1999 Microsoft Corporation. All rights reserved. ******************************************************************************/ #include "precomp.h"
#include "gdi.h"
#include "directx.h"
#include "clip.h"
//
// Maximal clip rectangle for trivial stretch clipping
//
// Note: SCISSOR_MAX is defined as 2047 because this is
// the maximum clip size P2 can handle.
// It is OK to set this maximum clip size since no device
// bitmap will be bigger than 2047. This is the limitation
// of P2 hardware. See DrvCreateDeviceBitmap() for more
// detail
//
RECTL grclStretchClipMax = { 0, 0, SCISSOR_MAX, SCISSOR_MAX };
//-----------------------------------------------------------------------------
//
// DWORD dwGetPixelSize()
//
// This routine converts current bitmap format to Permedia pixel size
//
//-----------------------------------------------------------------------------
DWORD dwGetPixelSize(ULONG ulBitmapFormat, DWORD* pdwFormatBits, DWORD* pdwFormatExtention) { DWORD dwPixelSize;
switch ( ulBitmapFormat ) { case BMF_8BPP: dwPixelSize = 0; *pdwFormatBits = PERMEDIA_8BIT_PALETTEINDEX; *pdwFormatExtention = PERMEDIA_8BIT_PALETTEINDEX_EXTENSION; break;
case BMF_16BPP: dwPixelSize = 1; *pdwFormatBits = PERMEDIA_565_RGB; *pdwFormatExtention = PERMEDIA_565_RGB_EXTENSION; break;
case BMF_32BPP: dwPixelSize = 2; *pdwFormatBits = PERMEDIA_888_RGB; *pdwFormatExtention = PERMEDIA_888_RGB_EXTENSION; break;
default: dwPixelSize = -1; }
return dwPixelSize; }// dwGetPixelSize()
//-----------------------------------------------------------------------------
//
// DWORD bStretchInit()
//
// This routine initializes all the registers needed for doing a stretch blt
//
//-----------------------------------------------------------------------------
BOOL bStretchInit(SURFOBJ* psoDst, SURFOBJ* psoSrc) { Surf* pSurfDst = (Surf*)psoDst->dhsurf; Surf* pSurfSrc = (Surf*)psoSrc->dhsurf; DWORD dwDstPixelSize; DWORD dwDstFormatBits; DWORD dwDstFormatExtention; DWORD dwSrcPixelSize; DWORD dwSrcFormatBits; DWORD dwSrcFormatExtention; PDev* ppdev = (PDev*)psoDst->dhpdev; ULONG* pBuffer;
DBG_GDI((6, "bStretchInit called")); ASSERTDD(pSurfSrc, "Not valid private surface in source"); ASSERTDD(pSurfDst, "Not valid private surface in destination");
dwDstPixelSize = dwGetPixelSize(psoDst->iBitmapFormat, &dwDstFormatBits, &dwDstFormatExtention);
if ( dwDstPixelSize == -1 ) { DBG_GDI((1, "bStretchBlt return FALSE because of wrong DstPixel Size")); //
// Unsupported bitmap format, return false
//
return FALSE; } InputBufferReserve(ppdev, 26, &pBuffer);
if ( dwDstPixelSize != __PERMEDIA_8BITPIXEL) { pBuffer[0] = __Permedia2TagDitherMode; pBuffer[1] = (COLOR_MODE << PM_DITHERMODE_COLORORDER) // RGB color order
|(dwDstFormatBits << PM_DITHERMODE_COLORFORMAT) |(dwDstFormatExtention << PM_DITHERMODE_COLORFORMATEXTENSION) |(1 << PM_DITHERMODE_ENABLE); } else { pBuffer[0] = __Permedia2TagDitherMode; pBuffer[1] = __PERMEDIA_DISABLE; }
pBuffer[2] = __Permedia2TagFBWindowBase; pBuffer[3] = pSurfDst->ulPixOffset;
//
// Set no read of source.
//
pBuffer[4] = __Permedia2TagFBReadMode; pBuffer[5] = PM_FBREADMODE_PARTIAL(pSurfDst->ulPackedPP); pBuffer[6] = __Permedia2TagLogicalOpMode; pBuffer[7] = __PERMEDIA_DISABLE; pBuffer[8] = __Permedia2TagTextureBaseAddress; pBuffer[9] = pSurfSrc->ulPixOffset; pBuffer[10] = __Permedia2TagTextureAddressMode; pBuffer[11] = 1 << PM_TEXADDRESSMODE_ENABLE; pBuffer[12] = __Permedia2TagTextureColorMode; pBuffer[13] = (1 << PM_TEXCOLORMODE_ENABLE) | (0 << 4) // RGB
| (_P2_TEXTURE_COPY << PM_TEXCOLORMODE_APPLICATION);
//
// Note: we have to turn off BiLinear filtering here, even for stretch
// because GDI doesn't do it. Otherwise, we will fail during the
// comparison
//
pBuffer[14] = __Permedia2TagTextureReadMode; pBuffer[15] = PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) | PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) | PM_TEXREADMODE_WIDTH(11) | PM_TEXREADMODE_HEIGHT(11);
dwSrcPixelSize = dwGetPixelSize(psoSrc->iBitmapFormat, &dwSrcFormatBits, &dwSrcFormatExtention);
if ( dwSrcPixelSize == -1 ) { DBG_GDI((1, "bStretchBlt return FALSE because of wrong SrcPixel Size")); //
// Unsupported bitmap format, return false
//
return FALSE; } pBuffer[16] = __Permedia2TagTextureDataFormat; pBuffer[17] = (dwSrcFormatBits << PM_TEXDATAFORMAT_FORMAT) | (dwSrcFormatExtention << PM_TEXDATAFORMAT_FORMATEXTENSION) | (COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER); pBuffer[18] = __Permedia2TagTextureMapFormat; pBuffer[19] = pSurfSrc->ulPackedPP |(dwSrcPixelSize << PM_TEXMAPFORMAT_TEXELSIZE); pBuffer[20] = __Permedia2TagScissorMode; pBuffer[21] = SCREEN_SCISSOR_DEFAULT | USER_SCISSOR_ENABLE; pBuffer[22] = __Permedia2TagdSdyDom; pBuffer[23] = 0; pBuffer[24] = __Permedia2TagdTdx; pBuffer[25] = 0;
pBuffer += 26; InputBufferCommit(ppdev, pBuffer);
DBG_GDI((6, "bStretchInit return TRUE")); return TRUE; }// bStretchInit()
//-----------------------------------------------------------------------------
//
// DWORD bStretchReset()
//
// This routine resets all the registers changed during stretch blt
//
//-----------------------------------------------------------------------------
void vStretchReset(PDev* ppdev) { ULONG* pBuffer; DBG_GDI((6, "vStretchReset called")); InputBufferReserve(ppdev, 12, &pBuffer); //
// Restore the default settings
//
pBuffer[0] = __Permedia2TagScissorMode; pBuffer[1] = SCREEN_SCISSOR_DEFAULT; pBuffer[2] = __Permedia2TagDitherMode; pBuffer[3] = __PERMEDIA_DISABLE; pBuffer[4] = __Permedia2TagTextureAddressMode; pBuffer[5] = __PERMEDIA_DISABLE; pBuffer[6] = __Permedia2TagTextureColorMode; pBuffer[7] = __PERMEDIA_DISABLE; pBuffer[8] = __Permedia2TagTextureReadMode; pBuffer[9] = __PERMEDIA_DISABLE; pBuffer[10] = __Permedia2TagdY; pBuffer[11] = INTtoFIXED(1);
pBuffer += 12; InputBufferCommit(ppdev, pBuffer);
DBG_GDI((6, "vStretchReset done")); return; }// vStretchReset()
//-----------------------------------------------------------------------------
//
// VOID vStretchBlt()
//
// This routine does the stretch blt work through the texture engine
//
//-----------------------------------------------------------------------------
VOID vStretchBlt(SURFOBJ* psoDst, SURFOBJ* psoSrc, RECTL* rDest, RECTL* rSrc, RECTL* prclClip) { Surf* pSurfDst = (Surf*)psoDst->dhsurf; Surf* pSurfSrc = (Surf*)psoSrc->dhsurf; LONG lXScale; LONG lYScale; DWORD dwDestWidth = rDest->right - rDest->left; DWORD dwDestHeight = rDest->bottom - rDest->top; DWORD dwSourceWidth = rSrc->right - rSrc->left; DWORD dwSourceHeight = rSrc->bottom - rSrc->top; DWORD dwRenderDirection; DWORD dwDstPixelSize; DWORD dwDstFormatBits; DWORD dwDstFormatExtention; DWORD dwSrcPixelSize; DWORD dwSrcFormatBits; DWORD dwSrcFormatExtention; ULONG* pBuffer; PDev* ppdev = (PDev*)psoDst->dhpdev;
DBG_GDI((6, "vStretchBlt called")); DBG_GDI((6, "prclClip (left, right, top, bottom)=(%d, %d, %d,%d)", prclClip->left, prclClip->right, prclClip->top, prclClip->bottom)); DBG_GDI((6, "rSrc (left, right, top, bottom=(%d, %d, %d,%d)",rSrc->left, rSrc->right, rSrc->top, rSrc->bottom)); DBG_GDI((6, "rDest (left, right, top, bottom)=(%d, %d, %d,%d)",rDest->left, rDest->right, rDest->top, rDest->bottom)); ASSERTDD(prclClip != NULL, "Wrong clippng rectangle");
//
// Note: the scale factor register value: dsDx, dTdyDom's interger part
// starts at bit 20. So we need to "<< 20" here
//
lXScale = (dwSourceWidth << 20) / dwDestWidth; lYScale = (dwSourceHeight << 20) / dwDestHeight; // lXScale = (((dwSourceWidth << 18) - 1) / dwDestWidth) << 2;
// lYScale = (((dwSourceHeight << 18) - 1) / dwDestHeight) << 2;
DBG_GDI((6, "lXScale=0x%x, lYScale=0x%x", lXScale, lYScale)); DBG_GDI((6, "dwSourceWidth=%d, dwDestWidth=%d", dwSourceWidth, dwDestWidth)); DBG_GDI((6, "dwSourceHeight=%d, dwDestHeight=%d", dwSourceHeight, dwDestHeight)); InputBufferReserve(ppdev, 24, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMinXY; pBuffer[1] = ((prclClip->left)<< SCISSOR_XOFFSET) |((prclClip->top)<< SCISSOR_YOFFSET); pBuffer[2] = __Permedia2TagScissorMaxXY; pBuffer[3] = ((prclClip->right)<< SCISSOR_XOFFSET) |((prclClip->bottom)<< SCISSOR_YOFFSET);
//
// We need to be carefull with overlapping rectangles
//
if ( (pSurfSrc->ulPixOffset) != (pSurfDst->ulPixOffset) ) { //
// Src and dst are differnt surface
//
dwRenderDirection = 1; } else { //
// Src and dst are the same surface
// We will set dwRenderDirection=1 if the src is lower or righter
// than the dst, that is, if it is bottom-up or right-left, we set
// dwRenderDirection=1, otherwise it = 0
//
if ( rSrc->top < rDest->top ) { dwRenderDirection = 0; } else if ( rSrc->top > rDest->top ) { dwRenderDirection = 1; } else if ( rSrc->left < rDest->left ) { dwRenderDirection = 0; } else { dwRenderDirection = 1; } }// src and dst are different
DBG_GDI((6, "dwRenderDirection=%d", dwRenderDirection));
//
// Render the rectangle
//
if ( dwRenderDirection ) { pBuffer[4] = __Permedia2TagSStart; pBuffer[5] = (rSrc->left << 20) + ((lXScale >> 1) & 0xfffffffc); pBuffer[6] = __Permedia2TagTStart; pBuffer[7] = (rSrc->top << 20) + ((lYScale >> 1) & 0xfffffffc); pBuffer[8] = __Permedia2TagdSdx; pBuffer[9] = lXScale; pBuffer[10] = __Permedia2TagdTdyDom; pBuffer[11] = lYScale; pBuffer[12] = __Permedia2TagStartXDom; pBuffer[13] = INTtoFIXED(rDest->left); pBuffer[14] = __Permedia2TagStartXSub; pBuffer[15] = INTtoFIXED(rDest->right); pBuffer[16] = __Permedia2TagStartY; pBuffer[17] = INTtoFIXED(rDest->top); pBuffer[18] = __Permedia2TagdY; pBuffer[19] = INTtoFIXED(1); pBuffer[20] = __Permedia2TagCount; pBuffer[21] = rDest->bottom - rDest->top; pBuffer[22] = __Permedia2TagRender; pBuffer[23] = __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE; } else { //
// Render right to left, bottom to top
//
pBuffer[4] = __Permedia2TagSStart; pBuffer[5] = (rSrc->right << 20) + ((lXScale >> 1)& 0xfffffffc); pBuffer[6] = __Permedia2TagTStart; pBuffer[7] = (rSrc->bottom << 20) - ((lYScale >> 1)& 0xfffffffc); lXScale = -lXScale; lYScale = -lYScale;
pBuffer[8] = __Permedia2TagdSdx; pBuffer[9] = lXScale; pBuffer[10] = __Permedia2TagdTdyDom; pBuffer[11] = lYScale; pBuffer[12] = __Permedia2TagStartXDom; pBuffer[13] = INTtoFIXED(rDest->right); pBuffer[14] = __Permedia2TagStartXSub; pBuffer[15] = INTtoFIXED(rDest->left); pBuffer[16] = __Permedia2TagStartY; pBuffer[17] = INTtoFIXED(rDest->bottom - 1); pBuffer[18] = __Permedia2TagdY; pBuffer[19] = (DWORD)INTtoFIXED(-1); pBuffer[20] = __Permedia2TagCount; pBuffer[21] = rDest->bottom - rDest->top; pBuffer[22] = __Permedia2TagRender; pBuffer[23] = __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_TEXTURED_PRIMITIVE; }
pBuffer += 24; InputBufferCommit(ppdev, pBuffer); DBG_GDI((6, "vStretchBlt done")); return; }// vStretchBlt()
//-----------------------------Public*Routine----------------------------------
//
// BOOL DrvStretchBlt
//
// DrvStretchBlt provides stretching bit-block transfer capabilities between any
// combination of device-managed and GDI-managed surfaces. This function enables
// the device driver to write to GDI bitmaps, especially when the driver can do
// halftoning. This function allows the same halftoning algorithm to be applied
// to GDI bitmaps and device surfaces.
//
// Parameters
// psoDest-----Points to a SURFOBJ that identifies the surface on which to draw
// psoSrc------Points to a SURFOBJ that defines the source for the bit-block
// transfer operation.
// psoMask-----This optional parameter points to a surface that provides a mask
// for the source. The mask is defined by a logic map, which is a
// bitmap with 1 bit per pixel.
// The mask limits the area of the source that is copied. If this
// parameter is specified, it has an implicit rop4 of 0xCCAA,
// meaning the source should be copied wherever the mask is one,
// but the destination should be left alone wherever the mask is
// zero.
//
// When this parameter is null there is an implicit rop4 of 0xCCCC,
// which means that the source should be copied everywhere in the
// source rectangle.
//
// The mask will always be large enough to contain the relevant
// source; tiling is unnecessary.
// pco---------Points to a CLIPOBJ that limits the area to be modified in the
// destination. GDI services are provided to enumerate the clip
// region as a set of rectangles.
// Whenever possible, GDI simplifies the clipping involved.
// However, unlike DrvBitBlt, DrvStretchBlt can be called with a
// single clipping rectangle. This prevents rounding errors in
// clipping the output.
// pxlo--------Points to a XLATEOBJ that specifies how color indices are to be
// translated between the source and target surfaces.
// The XLATEOBJ can also be queried to find the RGB color for any
// source index. A high quality stretching bit-block transfer will
// need to interpolate colors in some cases.
// pca---------Points to a COLORADJUSTMENT structure that defines the color
// adjustment values to be applied to the source bitmap before
// stretching the bits. (See the Platform SDK.)
// pptlHTOrg---Specifies the origin of the halftone brush. Device drivers that
// use halftone brushes should align the upper left pixel of the
// brush's pattern with this point on the device surface.
// prclDest----Points to a RECTL structure that defines the area to be modified
// in the coordinate system of the destination surface. This
// rectangle is defined by two points that are not necessarily well
// ordered, meaning the coordinates of the second point are not
// necessarily larger than those of the first point. The rectangle
// they describe does not include the lower and right edges. This
// function is never called with an empty destination rectangle.
//
// DrvStretchBlt can do inversions of x and y when the destination
// rectangle is not well ordered.
// prclSrc-----Points to a RECTL that defines the area that will be copied in
// the coordinate system of the source surface. The rectangle is
// defined by two points, and will map onto the rectangle defined
// by prclDest. The points of the source rectangle are well ordered
// This function is never given an empty source rectangle.
//
// The mapping is defined by prclSrc and prclDest. The points
// specified in prclDest and prclSrc lie on integer coordinates,
// which correspond to pixel centers. A rectangle defined by two
// such points is considered to be a geometric rectangle with two
// vertices whose coordinates are the given points, but with 0.5
// subtracted from each coordinate. (POINTL structures should be
// considered a shorthand notation for specifying these fractional
// coordinate vertices.)
//
// The edges of any rectangle never intersect a pixel, but go
// around a set of pixels. The pixels inside the rectangle are
// those expected for a "bottom-right exclusive" rectangle.
// DrvStretchBlt will map the geometric source rectangle exactly
// onto the geometric destination rectangle.
// pptlMask----Points to a POINTL structure that specifies which pixel in the
// given mask corresponds to the upper left pixel in the source
// rectangle. Ignore this parameter if no mask is specified.
// iMode-------Specifies how source pixels are combined to get output pixels.
// The HALFTONE mode is slower than the other modes, but produces
// higher quality images.
// Value Meaning
// WHITEONBLACK On a shrinking bit-block transfer, pixels
// should be combined with a Boolean OR
// operation. On a stretching bit-block
// transfer, pixels should be replicated.
// BLACKONWHITE On a shrinking bit-block transfer, pixels
// should be combined with a Boolean AND
// operation. On a stretching bit-block
// transfer, pixels should be replicated.
// COLORONCOLOR On a shrinking bit-block transfer, enough
// pixels should be ignored so that pixels
// don't need to be combined. On a stretching
// bit-block transfer, pixels should be
// replicated.
// HALFTONE The driver can use groups of pixels in the
// output surface to best approximate the color
// or gray level of the input.
//
// Return Value
// The return value is TRUE if the function is successful. Otherwise, it is
// FALSE, and an error code is logged.
//
// Comments
// This function can be provided to handle only certain forms of stretching,
// such as by integer multiples. If the driver has hooked the call and is asked
// to perform an operation it does not support, the driver should forward the
// data to EngStretchBlt for GDI to handle.
//
// If the driver wants GDI to handle halftoning, and wants to ensure the proper
// iMode value, the driver can hook DrvStretchBlt, set iMode to HALFTONE, and
// call back to GDI with EngStretchBlt with the set iMode value.
//
// DrvStretchBlt is optional for display drivers.
//
//-----------------------------------------------------------------------------
BOOL DrvStretchBlt(SURFOBJ* psoDst, SURFOBJ* psoSrc, SURFOBJ* psoMsk, CLIPOBJ* pco, XLATEOBJ* pxlo, COLORADJUSTMENT* pca, POINTL* pptlHTOrg, RECTL* prclDst, RECTL* prclSrc, POINTL* pptlMsk, ULONG iMode) { Surf* pSurfSrc = (Surf*)psoSrc->dhsurf; Surf* pSurfDst = (Surf*)psoDst->dhsurf; PDev* ppdev = (PDev*)psoDst->dhpdev; BYTE iDComplexity; RECTL* prclClip; ULONG cxDst; ULONG cyDst; ULONG cxSrc; ULONG cySrc; BOOL bMore; ClipEnum ceInfo; LONG lNumOfIntersections; LONG i;
DBG_GDI((6, "DrvStretchBlt called with iMode = %d", iMode)); if (iMode != COLORONCOLOR) { DBG_GDI((6, "Punt because iMode != COLORONCOLOR")); goto Punt_It; }
vCheckGdiContext(ppdev); //
// GDI guarantees us that for a StretchBlt the destination surface
// will always be in video memory, not in system memory
//
ASSERTDD(pSurfDst->flags & SF_VM, "Dest surface is not in video memory");
//
// If the source is not a driver created surface or currently not sit
// in the video memory, we just punt it back because GDI doing it will
// be faster
//
if ( (!pSurfSrc) || (pSurfSrc->flags & SF_SM) ) { DBG_GDI((6, "Punt because source = 0x%x or in sys memory", pSurfSrc)); goto Punt_It; }
//
// We don't do the stretch blt if the mask is not NULL or the translate is
// not trivial. We also don't do it if the source and current screen has
// different color depth
//
if ( (psoMsk == NULL) &&((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&((psoSrc->iBitmapFormat == ppdev->iBitmapFormat)) ) { cxDst = prclDst->right - prclDst->left; cyDst = prclDst->bottom - prclDst->top; cxSrc = prclSrc->right - prclSrc->left; cySrc = prclSrc->bottom - prclSrc->top;
//
// Our 'vStretchDIB' routine requires that the stretch be
// non-inverting, within a certain size, to have no source
// clipping, and to have no empty rectangles (the latter is the
// reason for the '- 1' on the unsigned compare here):
//
if ( ((cxSrc - 1) < STRETCH_MAX_EXTENT) &&((cySrc - 1) < STRETCH_MAX_EXTENT) &&((cxDst - 1) < STRETCH_MAX_EXTENT) &&((cyDst - 1) < STRETCH_MAX_EXTENT) &&(prclSrc->left >= 0) &&(prclSrc->top >= 0) &&(prclSrc->right <= psoSrc->sizlBitmap.cx) &&(prclSrc->bottom <= psoSrc->sizlBitmap.cy)) { if ( !bStretchInit(psoDst, psoSrc) ) { goto Punt_It; }
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if ( (iDComplexity == DC_TRIVIAL) || (iDComplexity == DC_RECT) ) { if (iDComplexity == DC_TRIVIAL) { DBG_GDI((7, "Trivial clipping"));
// If there is no clipping, we just set the clipping area
// as the maximum
prclClip = &grclStretchClipMax;
ASSERTDD(((prclClip->right >= prclDst->right) && (prclClip->bottom >= prclDst->bottom)), "Dest surface is larger than P2 can handle"); } else { DBG_GDI((7, "DC_RECT clipping")); prclClip = &pco->rclBounds; }
vStretchBlt(psoDst, psoSrc, prclDst, prclSrc, prclClip);
} else { DBG_GDI((7, "Complex clipping")); CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
//
// Enumerate all the clip rectangles
//
do { //
// Get one clip rectangle
//
bMore = CLIPOBJ_bEnum(pco, sizeof(ceInfo), (ULONG*)&ceInfo);
//
// Get the intersect region with the dest rectangle
//
lNumOfIntersections = cIntersect(prclDst, ceInfo.arcl, ceInfo.c);
//
// If there is clipping, then we do stretch region
// by region
//
if ( lNumOfIntersections != 0 ) { for ( i = 0; i < lNumOfIntersections; ++i ) { vStretchBlt(psoDst, psoSrc, prclDst, prclSrc, &ceInfo.arcl[i]); } } } while (bMore);
}// Non-DC rect clipping
DBG_GDI((6, "DrvStretchBlt return TRUE")); // Cleanup stretch settings
vStretchReset(ppdev); InputBufferFlush(ppdev); return TRUE; }// source/dest withnin range
}// No mask, trivial xlate, same BMP format
Punt_It: DBG_GDI((6, "DrvStretchBlt punt")); return(EngStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode)); }// DrvStretchBlt()
|