You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
26 KiB
692 lines
26 KiB
/******************************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()
|
|
|