Commit 6a1aa9b1 authored by Roderick Colenbrander's avatar Roderick Colenbrander Committed by Alexandre Julliard

winex11: XRenderComposite can be inaccurate when scaled x / y source coordinates are passed to it.

Moving this translation to the transformation matrix fixes the problem.
parent 75fc48d4
...@@ -1438,8 +1438,7 @@ static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT ...@@ -1438,8 +1438,7 @@ static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT
wine_tsx11_unlock(); wine_tsx11_unlock();
if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
xSrc, ySrc, widthSrc, heightSrc, widthSrc, heightSrc, widthDst, heightDst,
xDst, yDst, widthDst, heightDst,
&visRectSrc, &visRectDst)) &visRectSrc, &visRectDst))
{ {
if (fStretch) if (fStretch)
......
...@@ -269,9 +269,7 @@ extern BOOL X11DRV_XRender_ExtTextOut(X11DRV_PDEVICE *physDev, INT x, INT y, UIN ...@@ -269,9 +269,7 @@ extern BOOL X11DRV_XRender_ExtTextOut(X11DRV_PDEVICE *physDev, INT x, INT y, UIN
UINT count, const INT *lpDx); UINT count, const INT *lpDx);
BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst, BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
Pixmap pixmap, GC gc, Pixmap pixmap, GC gc,
INT xSrc, INT ySrc,
INT widthSrc, INT heightSrc, INT widthSrc, INT heightSrc,
INT xDst, INT yDst,
INT widthDst, INT heightDst, INT widthDst, INT heightDst,
RECT *visRectSrc, RECT *visRectDst); RECT *visRectSrc, RECT *visRectDst);
extern void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev); extern void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev);
......
...@@ -1733,6 +1733,41 @@ static void set_xrender_transformation(Picture src_pict, float xscale, float ysc ...@@ -1733,6 +1733,41 @@ static void set_xrender_transformation(Picture src_pict, float xscale, float ysc
#endif #endif
} }
/* Helper function for (stretched) blitting using xrender */
static void xrender_blit(Picture src_pict, Picture mask_pict, Picture dst_pict, int x_src, int y_src, float xscale, float yscale, int width, int height)
{
/* Further down a transformation matrix is used for stretching and mirroring the source data.
* xscale/yscale contain the scaling factors for the width and height. In case of mirroring
* we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
*/
int x_offset = (xscale<0) ? width : 0;
int y_offset = (yscale<0) ? height : 0;
/* When we need to scale we perform scaling and source_x / source_y translation using a transformation matrix.
* This is needed because XRender is inaccurate in combination with scaled source coordinates passed to XRenderComposite.
* In all other cases we do use XRenderComposite for translation as it is faster than using a transformation matrix. */
if(xscale != 1.0 || yscale != 1.0)
{
/* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
if(mask_pict)
set_xrender_transformation(mask_pict, xscale, yscale, x_offset, y_offset);
else
set_xrender_transformation(src_pict, xscale, yscale, x_src + x_offset, y_src + y_offset);
pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, 0, 0, 0, 0, 0, 0, width, height);
}
else
{
/* When we are using a mask, 'src_pict' contains a 1x1 picture for tiling, the actual source data is in mask_pict */
if(mask_pict)
set_xrender_transformation(mask_pict, 1, 1, 0, 0);
else
set_xrender_transformation(src_pict, 1, 1, 0, 0);
pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict, x_src, y_src, 0, 0, 0, 0, width, height);
}
}
/****************************************************************************** /******************************************************************************
* AlphaBlend (x11drv.@) * AlphaBlend (x11drv.@)
*/ */
...@@ -1933,34 +1968,28 @@ BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT wid ...@@ -1933,34 +1968,28 @@ BOOL CDECL X11DRV_AlphaBlend(X11DRV_PDEVICE *devDst, INT xDst, INT yDst, INT wid
BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst, BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
Pixmap pixmap, GC gc, Pixmap pixmap, GC gc,
INT xSrc, INT ySrc,
INT widthSrc, INT heightSrc, INT widthSrc, INT heightSrc,
INT xDst, INT yDst,
INT widthDst, INT heightDst, INT widthDst, INT heightDst,
RECT *visRectSrc, RECT *visRectDst ) RECT *visRectSrc, RECT *visRectDst )
{ {
BOOL stretch = (widthSrc != widthDst) || (heightSrc != heightDst); BOOL stretch = (widthSrc != widthDst) || (heightSrc != heightDst);
int width = visRectDst->right - visRectDst->left; int width = visRectDst->right - visRectDst->left;
int height = visRectDst->bottom - visRectDst->top; int height = visRectDst->bottom - visRectDst->top;
int x_src = physDevSrc->dc_rect.left + visRectSrc->left;
int y_src = physDevSrc->dc_rect.top + visRectSrc->top;
WineXRenderFormat *src_format = get_xrender_format_from_pdevice(physDevSrc); WineXRenderFormat *src_format = get_xrender_format_from_pdevice(physDevSrc);
WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(physDevDst); WineXRenderFormat *dst_format = get_xrender_format_from_pdevice(physDevDst);
Picture src_pict=0, dst_pict=0, mask_pict=0; Picture src_pict=0, dst_pict=0, mask_pict=0;
/* Further down a transformation matrix is used for stretching and mirroring the source data.
* xscale/yscale contain the scaling factors for the width and height. In case of mirroring
* we also need a x- and y-offset because without the pixels will be in the wrong quadrant of the x-y plane.
*/
double xscale = widthSrc/(double)widthDst; double xscale = widthSrc/(double)widthDst;
double yscale = heightSrc/(double)heightDst; double yscale = heightSrc/(double)heightDst;
int xoffset = (xscale<0) ? width : 0;
int yoffset = (yscale<0) ? height : 0;
XRenderPictureAttributes pa; XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors; pa.subwindow_mode = IncludeInferiors;
pa.repeat = RepeatNone; pa.repeat = RepeatNone;
TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc->depth, widthSrc, heightSrc, xSrc, ySrc); TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc->depth, widthSrc, heightSrc, x_src, y_src);
TRACE("dst depth=%d widthDst=%d heightDst=%d xDst=%d yDst=%d\n", physDevDst->depth, widthDst, heightDst, xDst, yDst); TRACE("dst depth=%d widthDst=%d heightDst=%d\n", physDevDst->depth, widthDst, heightDst);
if(!X11DRV_XRender_Installed) if(!X11DRV_XRender_Installed)
{ {
...@@ -1981,10 +2010,7 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE ...@@ -1981,10 +2010,7 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
{ {
TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n"); TRACE("Source and destination depth match and no stretching needed falling back to XCopyArea\n");
wine_tsx11_lock(); wine_tsx11_lock();
XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
physDevSrc->dc_rect.left + visRectSrc->left,
physDevSrc->dc_rect.top + visRectSrc->top,
width, height, 0, 0);
wine_tsx11_unlock(); wine_tsx11_unlock();
return TRUE; return TRUE;
} }
...@@ -1998,7 +2024,6 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE ...@@ -1998,7 +2024,6 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
/* We use the source drawable as a mask */ /* We use the source drawable as a mask */
wine_tsx11_lock(); wine_tsx11_lock();
mask_pict = pXRenderCreatePicture(gdi_display, physDevSrc->drawable, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa); mask_pict = pXRenderCreatePicture(gdi_display, physDevSrc->drawable, src_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
set_xrender_transformation(mask_pict, xscale, yscale, xoffset, yoffset);
/* Use backgroundPixel as the foreground color */ /* Use backgroundPixel as the foreground color */
src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel); src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
...@@ -2007,12 +2032,7 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE ...@@ -2007,12 +2032,7 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa); dst_pict = pXRenderCreatePicture(gdi_display, pixmap, dst_format->pict_format, CPSubwindowMode|CPRepeat, &pa);
pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height); pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &col, 0, 0, width, height);
/* Notice that the source coordinates have to be relative to the transformated source picture */ xrender_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict,
(physDevSrc->dc_rect.left + visRectSrc->left)/xscale,
(physDevSrc->dc_rect.top + visRectSrc->top)/yscale,
0, 0, 0, 0,
width, height);
if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict); if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
if(mask_pict) pXRenderFreePicture(gdi_display, mask_pict); if(mask_pict) pXRenderFreePicture(gdi_display, mask_pict);
...@@ -2024,18 +2044,12 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE ...@@ -2024,18 +2044,12 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
src_pict = pXRenderCreatePicture(gdi_display, src_pict = pXRenderCreatePicture(gdi_display,
physDevSrc->drawable, src_format->pict_format, physDevSrc->drawable, src_format->pict_format,
CPSubwindowMode|CPRepeat, &pa); CPSubwindowMode|CPRepeat, &pa);
set_xrender_transformation(src_pict, xscale, yscale, xoffset, yoffset);
dst_pict = pXRenderCreatePicture(gdi_display, dst_pict = pXRenderCreatePicture(gdi_display,
pixmap, dst_format->pict_format, pixmap, dst_format->pict_format,
CPSubwindowMode|CPRepeat, &pa); CPSubwindowMode|CPRepeat, &pa);
/* Notice that the source coordinates have to be relative to the transformated source picture */ xrender_blit(src_pict, 0, dst_pict, x_src, y_src, xscale, yscale, width, height);
pXRenderComposite(gdi_display, PictOpSrc, src_pict, mask_pict, dst_pict,
(physDevSrc->dc_rect.left + visRectSrc->left)/xscale,
(physDevSrc->dc_rect.top + visRectSrc->top)/yscale,
0, 0, 0, 0,
width, height);
if(src_pict) pXRenderFreePicture(gdi_display, src_pict); if(src_pict) pXRenderFreePicture(gdi_display, src_pict);
if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict); if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment