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

Alexandre Julliard julliard at winehq.org
Fri Jul 24 08:49:44 CDT 2009


Module: wine
Branch: master
Commit: 6a1aa9b166a571b219c317a59a000031cd2448ef
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=6a1aa9b166a571b219c317a59a000031cd2448ef

Author: Roderick Colenbrander <thunderbird2k at gmail.com>
Date:   Wed Jul 22 17:42:14 2009 +0200

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.

---

 dlls/winex11.drv/bitblt.c  |    3 +-
 dlls/winex11.drv/x11drv.h  |    2 -
 dlls/winex11.drv/xrender.c |   70 ++++++++++++++++++++++++++-----------------
 3 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c
index 79078ae..119ac5b 100644
--- a/dlls/winex11.drv/bitblt.c
+++ b/dlls/winex11.drv/bitblt.c
@@ -1438,8 +1438,7 @@ static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT
         wine_tsx11_unlock();
 
         if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
-                                              xSrc, ySrc, widthSrc, heightSrc,
-                                              xDst, yDst, widthDst, heightDst,
+                                              widthSrc, heightSrc, widthDst, heightDst,
                                               &visRectSrc, &visRectDst))
         {
             if (fStretch)
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 10af183..1a7a634 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -269,9 +269,7 @@ extern BOOL X11DRV_XRender_ExtTextOut(X11DRV_PDEVICE *physDev, INT x, INT y, UIN
 				      UINT count, const INT *lpDx);
 BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
                                       Pixmap pixmap, GC gc,
-                                      INT xSrc, INT ySrc,
                                       INT widthSrc, INT heightSrc,
-                                      INT xDst, INT yDst,
                                       INT widthDst, INT heightDst,
                                       RECT *visRectSrc, RECT *visRectDst);
 extern void X11DRV_XRender_UpdateDrawable(X11DRV_PDEVICE *physDev);
diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c
index 6d290ba..072cd25 100644
--- a/dlls/winex11.drv/xrender.c
+++ b/dlls/winex11.drv/xrender.c
@@ -1733,6 +1733,41 @@ static void set_xrender_transformation(Picture src_pict, float xscale, float ysc
 #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.@)
  */
@@ -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,
                                       Pixmap pixmap, GC gc,
-                                      INT xSrc, INT ySrc,
                                       INT widthSrc, INT heightSrc,
-                                      INT xDst, INT yDst,
                                       INT widthDst, INT heightDst,
                                       RECT *visRectSrc, RECT *visRectDst )
 {
     BOOL stretch = (widthSrc != widthDst) || (heightSrc != heightDst);
     int width = visRectDst->right - visRectDst->left;
     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 *dst_format = get_xrender_format_from_pdevice(physDevDst);
     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 yscale = heightSrc/(double)heightDst;
-    int xoffset = (xscale<0) ? width : 0;
-    int yoffset = (yscale<0) ? height : 0;
 
     XRenderPictureAttributes pa;
     pa.subwindow_mode = IncludeInferiors;
     pa.repeat = RepeatNone;
 
-    TRACE("src depth=%d widthSrc=%d heightSrc=%d xSrc=%d ySrc=%d\n", physDevSrc->depth, widthSrc, heightSrc, xSrc, ySrc);
-    TRACE("dst depth=%d widthDst=%d heightDst=%d xDst=%d yDst=%d\n", physDevDst->depth, widthDst, heightDst, xDst, yDst);
+    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\n", physDevDst->depth, widthDst, heightDst);
 
     if(!X11DRV_XRender_Installed)
     {
@@ -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");
         wine_tsx11_lock();
-        XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
-                    physDevSrc->dc_rect.left + visRectSrc->left,
-                    physDevSrc->dc_rect.top + visRectSrc->top,
-                    width, height, 0, 0);
+        XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, x_src, y_src, width, height, 0, 0);
         wine_tsx11_unlock();
         return TRUE;
     }
@@ -1998,7 +2024,6 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
         /* We use the source drawable as a mask */
         wine_tsx11_lock();
         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 */
         src_pict = get_tile_pict(dst_format, physDevDst->backgroundPixel);
@@ -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);
         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 */
-        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);
+        xrender_blit(src_pict, mask_pict, dst_pict, x_src, y_src, xscale, yscale, width, height);
 
         if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);
         if(mask_pict) pXRenderFreePicture(gdi_display, mask_pict);
@@ -2024,18 +2044,12 @@ BOOL X11DRV_XRender_GetSrcAreaStretch(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE
         src_pict = pXRenderCreatePicture(gdi_display,
                                           physDevSrc->drawable, src_format->pict_format,
                                           CPSubwindowMode|CPRepeat, &pa);
-        set_xrender_transformation(src_pict, xscale, yscale, xoffset, yoffset);
 
         dst_pict = pXRenderCreatePicture(gdi_display,
                                           pixmap, dst_format->pict_format,
                                           CPSubwindowMode|CPRepeat, &pa);
 
-        /* Notice that the source coordinates have to be relative to the transformated source picture */
-        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);
+        xrender_blit(src_pict, 0, dst_pict, x_src, y_src, xscale, yscale, width, height);
 
         if(src_pict) pXRenderFreePicture(gdi_display, src_pict);
         if(dst_pict) pXRenderFreePicture(gdi_display, dst_pict);




More information about the wine-cvs mailing list