winex11: Fall back to the DIB engine for client-side stretching.

This commit is contained in:
Alexandre Julliard 2011-09-28 11:27:19 +02:00
parent 6e80c49fc9
commit 6861f4c252
1 changed files with 4 additions and 346 deletions

View File

@ -52,9 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
#define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */ #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
#define SWAP_INT32(i1,i2) \
do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] = static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
{ {
{ OP(PAT,DST,GXclear) }, /* 0x00 0 */ { OP(PAT,DST,GXclear) }, /* 0x00 0 */
@ -618,339 +615,6 @@ static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
} }
/***********************************************************************
* BITBLT_StretchRow
*
* Stretch a row of pixels. Helper function for BITBLT_StretchImage.
*/
static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
INT startDst, INT widthDst,
INT xinc, INT xoff, WORD mode )
{
register INT xsrc = xinc * startDst + xoff;
rowDst += startDst;
switch(mode)
{
case STRETCH_ANDSCANS:
for(; widthDst > 0; widthDst--, xsrc += xinc)
*rowDst++ &= rowSrc[xsrc >> 16];
break;
case STRETCH_ORSCANS:
for(; widthDst > 0; widthDst--, xsrc += xinc)
*rowDst++ |= rowSrc[xsrc >> 16];
break;
case STRETCH_DELETESCANS:
for(; widthDst > 0; widthDst--, xsrc += xinc)
*rowDst++ = rowSrc[xsrc >> 16];
break;
}
}
/***********************************************************************
* BITBLT_ShrinkRow
*
* Shrink a row of pixels. Helper function for BITBLT_StretchImage.
*/
static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
INT startSrc, INT widthSrc,
INT xinc, INT xoff, WORD mode )
{
register INT xdst = xinc * startSrc + xoff;
rowSrc += startSrc;
switch(mode)
{
case STRETCH_ORSCANS:
for(; widthSrc > 0; widthSrc--, xdst += xinc)
rowDst[xdst >> 16] |= *rowSrc++;
break;
case STRETCH_ANDSCANS:
for(; widthSrc > 0; widthSrc--, xdst += xinc)
rowDst[xdst >> 16] &= *rowSrc++;
break;
case STRETCH_DELETESCANS:
for(; widthSrc > 0; widthSrc--, xdst += xinc)
rowDst[xdst >> 16] = *rowSrc++;
break;
}
}
/***********************************************************************
* BITBLT_GetRow
*
* Retrieve a row from an image. Helper function for BITBLT_StretchImage.
*/
static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
INT start, INT width, INT depthDst,
int fg, int bg, unsigned long pixel_mask, BOOL swap)
{
register INT i;
assert( (row >= 0) && (row < image->height) );
assert( (start >= 0) && (width <= image->width) );
pdata += swap ? start+width-1 : start;
if (image->depth == depthDst) /* color -> color */
{
if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
if (swap) for (i = 0; i < width; i++)
*pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
else for (i = 0; i < width; i++)
*pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
else
if (swap) for (i = 0; i < width; i++)
*pdata-- = XGetPixel( image, i, row );
else for (i = 0; i < width; i++)
*pdata++ = XGetPixel( image, i, row );
}
else
{
if (image->depth == 1) /* monochrome -> color */
{
if (X11DRV_PALETTE_XPixelToPalette)
{
fg = X11DRV_PALETTE_XPixelToPalette[fg];
bg = X11DRV_PALETTE_XPixelToPalette[bg];
}
if (swap) for (i = 0; i < width; i++)
*pdata-- = XGetPixel( image, i, row ) ? bg : fg;
else for (i = 0; i < width; i++)
*pdata++ = XGetPixel( image, i, row ) ? bg : fg;
}
else /* color -> monochrome */
{
if (swap) for (i = 0; i < width; i++)
*pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
else for (i = 0; i < width; i++)
*pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
}
}
}
/***********************************************************************
* BITBLT_StretchImage
*
* Stretch an X image.
* FIXME: does not work for full 32-bit coordinates.
*/
static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
INT widthSrc, INT heightSrc,
INT widthDst, INT heightDst,
RECT *visRectSrc, RECT *visRectDst,
int foreground, int background,
unsigned long pixel_mask, WORD mode )
{
int *rowSrc, *rowDst, *pixel;
char *pdata;
INT xinc, xoff, yinc, ysrc, ydst;
register INT x, y;
BOOL hstretch, vstretch, hswap, vswap;
hswap = widthSrc * widthDst < 0;
vswap = heightSrc * heightDst < 0;
widthSrc = abs(widthSrc);
heightSrc = abs(heightSrc);
widthDst = abs(widthDst);
heightDst = abs(heightDst);
if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
(widthSrc+widthDst)*sizeof(int) ))) return;
rowDst = rowSrc + widthSrc;
/* When stretching, all modes are the same, and DELETESCANS is faster */
if ((widthSrc < widthDst) && (heightSrc < heightDst))
mode = STRETCH_DELETESCANS;
if (mode == STRETCH_HALFTONE) /* FIXME */
mode = STRETCH_DELETESCANS;
if (mode != STRETCH_DELETESCANS)
memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
widthDst*sizeof(int) );
hstretch = (widthSrc < widthDst);
vstretch = (heightSrc < heightDst);
if (hstretch)
{
xinc = (widthSrc << 16) / widthDst;
xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
}
else
{
xinc = ((int)widthDst << 16) / widthSrc;
xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
}
wine_tsx11_lock();
if (vstretch)
{
yinc = (heightSrc << 16) / heightDst;
ydst = visRectDst->top;
if (vswap)
{
ysrc = yinc * (heightDst - ydst - 1);
yinc = -yinc;
}
else
ysrc = yinc * ydst;
for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
{
if (((ysrc >> 16) < visRectSrc->top) ||
((ysrc >> 16) >= visRectSrc->bottom)) continue;
/* Retrieve a source row */
BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
visRectSrc->left, visRectSrc->right - visRectSrc->left,
dstImage->depth, foreground, background, pixel_mask, hswap );
/* Stretch or shrink it */
if (hstretch)
BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
visRectDst->right - visRectDst->left,
xinc, xoff, mode );
else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
visRectSrc->right - visRectSrc->left,
xinc, xoff, mode );
/* Store the destination row */
pixel = rowDst + visRectDst->right - 1;
y = ydst - visRectDst->top;
for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
XPutPixel( dstImage, x, y, *pixel-- );
if (mode != STRETCH_DELETESCANS)
memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
widthDst*sizeof(int) );
/* Make copies of the destination row */
pdata = dstImage->data + dstImage->bytes_per_line * y;
while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
(ydst < visRectDst->bottom-1))
{
memcpy( pdata + dstImage->bytes_per_line, pdata,
dstImage->bytes_per_line );
pdata += dstImage->bytes_per_line;
ysrc += yinc;
ydst++;
}
}
}
else /* Shrinking */
{
yinc = (heightDst << 16) / heightSrc;
ysrc = visRectSrc->top;
ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
if (vswap)
{
ydst += yinc * (heightSrc - ysrc - 1);
yinc = -yinc;
}
else
ydst += yinc * ysrc;
for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
{
if (((ydst >> 16) < visRectDst->top) ||
((ydst >> 16) >= visRectDst->bottom)) continue;
/* Retrieve a source row */
BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
visRectSrc->left, visRectSrc->right - visRectSrc->left,
dstImage->depth, foreground, background, pixel_mask, hswap );
/* Stretch or shrink it */
if (hstretch)
BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
visRectDst->right - visRectDst->left,
xinc, xoff, mode );
else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
visRectSrc->right - visRectSrc->left,
xinc, xoff, mode );
/* Merge several source rows into the destination */
if (mode == STRETCH_DELETESCANS)
{
/* Simply skip the overlapping rows */
while (((ydst + yinc) >> 16 == ydst >> 16) &&
(ysrc < visRectSrc->bottom-1))
{
ydst += yinc;
ysrc++;
}
}
else if (((ydst + yinc) >> 16 == ydst >> 16) &&
(ysrc < visRectSrc->bottom-1))
continue; /* Restart loop for next overlapping row */
/* Store the destination row */
pixel = rowDst + visRectDst->right - 1;
y = (ydst >> 16) - visRectDst->top;
for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
XPutPixel( dstImage, x, y, *pixel-- );
if (mode != STRETCH_DELETESCANS)
memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
widthDst*sizeof(int) );
}
}
wine_tsx11_unlock();
HeapFree( GetProcessHeap(), 0, rowSrc );
}
/***********************************************************************
* BITBLT_GetSrcAreaStretch
*
* Retrieve an area from the source DC, stretching and mapping all the
* pixels to Windows colors.
*/
static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
Pixmap pixmap, GC gc,
const struct bitblt_coords *src, const struct bitblt_coords *dst )
{
XImage *imageSrc, *imageDst;
RECT rectSrc = src->visrect;
RECT rectDst = dst->visrect;
int fg, bg;
OffsetRect( &rectSrc, -src->x, -src->y );
OffsetRect( &rectDst, -dst->x, -dst->y );
if (src->width < 0) OffsetRect( &rectSrc, -src->width, 0 );
if (dst->width < 0) OffsetRect( &rectDst, -dst->width, 0 );
if (src->height < 0) OffsetRect( &rectSrc, 0, -src->height );
if (dst->height < 0) OffsetRect( &rectDst, 0, -dst->height );
get_colors(physDevDst, physDevSrc, &fg, &bg);
wine_tsx11_lock();
/* FIXME: avoid BadMatch errors */
imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
physDevSrc->dc_rect.left + src->visrect.left,
physDevSrc->dc_rect.top + src->visrect.top,
src->visrect.right - src->visrect.left,
src->visrect.bottom - src->visrect.top,
AllPlanes, ZPixmap );
wine_tsx11_unlock();
imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
rectDst.bottom - rectDst.top, physDevDst->depth );
BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
dst->width, dst->height, &rectSrc, &rectDst,
fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
wine_tsx11_lock();
XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
XDestroyImage( imageSrc );
X11DRV_DIB_DestroyXImage( imageDst );
wine_tsx11_unlock();
return 0; /* no exposure events generated */
}
/*********************************************************************** /***********************************************************************
* BITBLT_GetSrcArea * BITBLT_GetSrcArea
* *
@ -1313,20 +977,18 @@ BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
{ {
X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev ); X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
BOOL fStretch;
INT width, height; INT width, height;
const BYTE *opcode; const BYTE *opcode;
Pixmap src_pixmap; Pixmap src_pixmap;
GC tmpGC; GC tmpGC;
if (src_dev->funcs != dst_dev->funcs) if (src_dev->funcs != dst_dev->funcs ||
src->width != dst->width || src->height != dst->height) /* no stretching with core X11 */
{ {
dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt ); dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop ); return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
} }
fStretch = (src->width != dst->width) || (src->height != dst->height);
width = dst->visrect.right - dst->visrect.left; width = dst->visrect.right - dst->visrect.left;
height = dst->visrect.bottom - dst->visrect.top; height = dst->visrect.bottom - dst->visrect.top;
@ -1336,7 +998,7 @@ BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
/* a few optimizations for single-op ROPs */ /* a few optimizations for single-op ROPs */
if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)) if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
{ {
if (same_format(physDevSrc, physDevDst)) if (same_format(physDevSrc, physDevDst))
{ {
@ -1385,11 +1047,7 @@ BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth ); src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
wine_tsx11_unlock(); wine_tsx11_unlock();
if (fStretch) BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
else
BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop ); execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
wine_tsx11_lock(); wine_tsx11_lock();