[PATCH] Xext: XCopyArea() does not work in Xinerama. Bug#:25113

arvind Umrao Arvind.Umrao at Sun.COM
Tue Nov 17 22:03:35 PST 2009


Request for review of patch attached in this email.

-Arvind

 From 15b4f89262bd77657d4159e029eab4c599ae0abc Mon Sep 17 00:00:00 2001
From: Arvind Umrao <arvind.umrao at sun.com>
Date: Mon, 16 Nov 2009 16:49:44 +0530
Subject: [PATCH] Xext: XCopyArea() does not work in Xinerama. Bug#:25113


XCopyArea() does not work in Xinerama mode. XCopyArea() does not copy 
areas of the screen between physical displays.

Description of the change:
This bug was first reported for Xsun. Two months back I have fixed 
Xsun,in Nevada. Xserver team in SUN reviewed my code changes.

Xcopy does not work, when we xcopy image from one screen to other in 
Xinerama mode. The solution to the problem is use internal xcopy  
instead of regular xcopy. Lines of code I have added is to detect if 
copied image( destination coordinate) not lies in same  screen of source 
image, then call internal xcopy instead of regular xcopy.
*1) Internal Xcopy*
In Internal Xcopy  temporary buffer is allocated and Xineramadata is 
copied .  Size of temporary buffer is same as drawing object(stuff). 
GetImage reads the image(Xineramadata) from all intersection boxes. When 
image overlaps between two or more screens, we can visualize portion of 
image in intersection boxes.

*2) Regular xcopy*
*Regular xcopy calls the regular copyimage. Regular copyimage will be 
much faster, because it does not call  getimage or putimage.*


My code changes are well commented.

*Testing*
a)I have tested my fixes using two XVR2500 frame buffer on SPARC Ultra 
45 with Xinerama on.
b)Also I have tested my fixes on Sunray with Xinerama on.


X.Org Bug 25113 <http://bugs.freedesktop.org/show_bug.cgi?id=25113>


Signed-off-by: Arvind Umrao <arvind.umrao at sun.com>
---
 Xext/panoramiXprocs.c |  354 
+++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 354 insertions(+), 0 deletions(-)

diff --git a/Xext/panoramiXprocs.c b/Xext/panoramiXprocs.c
index 6834efb..7011356 100644
--- a/Xext/panoramiXprocs.c
+++ b/Xext/panoramiXprocs.c
@@ -59,6 +59,144 @@ Equipment Corporation.
  */
 extern XID clientErrorValue;   /* XXX this is a kludge */
 
+/*
+ * calculate the overlap area of image when image overlaps two screens 
of Xinerama
+ *
+ * getRgn is used by PanoramiXCopyArea
+ *
+ */
+
+RegionPtr getRgn(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,
+                  GCPtr pGC,int srcx,int srcy,int width,int height,int 
dstx,int dsty)
+{
+    register ScreenPtr pscr = pGC->pScreen;
+    RegionPtr prgnSrcClip;      /* drawable-relative source clip */
+    RegionRec rgnSrcRec;
+    RegionPtr prgnDstClip;      /* drawable-relative dest clip */
+    RegionRec rgnDstRec;
+    BoxRec srcBox;              /* unclipped source */
+    RegionRec rgnExposed;       /* exposed region, calculated source-
+                                   relative, made dst relative to
+                                   intersect with visible parts of
+                                   dest and send events to client,
+                                   and then screen relative to paint
+                                   the window background
+                                */
+    WindowPtr pSrcWin;
+    BoxRec expBox;
+    Bool extents;
+
+    /* avoid work if we can */
+    if (!pGC->graphicsExposures &&
+        (pDstDrawable->type == DRAWABLE_PIXMAP) &&
+        ((pSrcDrawable->type == DRAWABLE_PIXMAP) ||
+         (((WindowPtr)pSrcDrawable)->backStorage == NULL)))
+        return NULL;
+
+    srcBox.x1 = srcx;
+    srcBox.y1 = srcy;
+    srcBox.x2 = srcx+width;
+    srcBox.y2 = srcy+height;
+
+    if (pSrcDrawable->type != DRAWABLE_PIXMAP)
+    {
+        BoxRec TsrcBox;
+
+        TsrcBox.x1 = srcx + pSrcDrawable->x;
+        TsrcBox.y1 = srcy + pSrcDrawable->y;
+        TsrcBox.x2 = TsrcBox.x1 + width;
+        TsrcBox.y2 = TsrcBox.y1 + height;
+        pSrcWin = (WindowPtr) pSrcDrawable;
+        if (pGC->subWindowMode == IncludeInferiors)
+        {
+            prgnSrcClip = NotClippedByChildren (pSrcWin);
+            if ((RECT_IN_REGION(pscr, prgnSrcClip, &TsrcBox)) == rgnIN)
+            {
+                REGION_DESTROY(pscr, prgnSrcClip);
+                return NULL;
+            }
+        }
+        else
+        {
+            if ((RECT_IN_REGION(pscr, &pSrcWin->clipList, &TsrcBox)) == 
rgnIN)
+                return NULL;
+            prgnSrcClip = &rgnSrcRec;
+            REGION_INIT(pscr, prgnSrcClip, NullBox, 0);
+            REGION_COPY(pscr, prgnSrcClip, &pSrcWin->clipList);
+        }
+        REGION_TRANSLATE(pscr, prgnSrcClip,
+                                -pSrcDrawable->x, -pSrcDrawable->y);
+    }
+    else
+    {
+        BoxRec  box;
+
+        if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) &&
+            (srcBox.x2 <= pSrcDrawable->width) &&
+            (srcBox.y2 <= pSrcDrawable->height))
+            return NULL;
+
+        box.x1 = 0;
+        box.y1 = 0;
+        box.x2 = pSrcDrawable->width;
+        box.y2 = pSrcDrawable->height;
+        prgnSrcClip = &rgnSrcRec;
+        REGION_INIT(pscr, prgnSrcClip, &box, 1);
+        pSrcWin = (WindowPtr)NULL;
+    }
+
+    if (pDstDrawable == pSrcDrawable)
+    {
+        prgnDstClip = prgnSrcClip;
+    }
+    else if (pDstDrawable->type != DRAWABLE_PIXMAP)
+    {
+        if (pGC->subWindowMode == IncludeInferiors)
+        {
+            prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable);
+        }
+        else
+        {
+            prgnDstClip = &rgnDstRec;
+            REGION_INIT(pscr, prgnDstClip, NullBox, 0);
+            REGION_COPY(pscr, prgnDstClip,
+                                &((WindowPtr)pDstDrawable)->clipList);
+        }
+        REGION_TRANSLATE(pscr, prgnDstClip,
+                                 -pDstDrawable->x, -pDstDrawable->y);
+    }
+    else
+    {
+        BoxRec  box;
+
+        box.x1 = 0;
+        box.y1 = 0;
+        box.x2 = pDstDrawable->width;
+        box.y2 = pDstDrawable->height;
+        prgnDstClip = &rgnDstRec;
+        REGION_INIT(pscr, prgnDstClip, &box, 1);
+    }
+
+    /* drawable-relative source region */
+    REGION_INIT(pscr, &rgnExposed, &srcBox, 1);
+
+    /* now get the hidden parts of the source box*/
+    REGION_SUBTRACT(pscr, &rgnExposed, &rgnExposed, prgnSrcClip);
+    /* move them over the destination */
+    REGION_TRANSLATE(pscr, &rgnExposed, dstx-srcx, dsty-srcy);
+
+    /* intersect with visible areas of dest */
+    REGION_INTERSECT(pscr, &rgnExposed, &rgnExposed, prgnDstClip);
+
+    {
+        /* don't look */
+        RegionPtr exposed = REGION_CREATE(pscr, NullBox, 0);
+        *exposed = rgnExposed;
+        return exposed;
+    }
+}
+
+
 int PanoramiXCreateWindow(ClientPtr client)
 {
     PanoramiXRes *parent, *newWin;
@@ -1090,6 +1228,222 @@ int PanoramiXCopyArea(ClientPtr client)
     xfree(data);
 
     result = Success;
+    } else if (src->type == XRT_WINDOW){
+
+        DrawablePtr pDst = NULL, pSrc = NULL;
+    GCPtr pGC = NULL;
+    RegionPtr pRgn[MAXSCREENS];
+    int rc;
+        DrawablePtr drawables[MAXSCREENS];
+        char *data = NULL;
+    size_t data_size;
+    int pitch;
+    int cross_screen = 0, rsrcFlag = 0;
+    int rsrcx = 0, rsrcy = 0, rsrcx2 = stuff->width, rsrcy2 = 
stuff->height;
+
+        bzero(pRgn, sizeof(RegionPtr) * MAXSCREENS);
+
+    /*
+         * Lines of code I have added is to detect if copied image( 
destination coordinate)
+         * not lies in same  screen of source image, then call internal 
xcopy instead of regular xcopy.
+         * There are two cases only when destination image will not lie 
in same sceen.
+         * a) right and bottom coordinates of copied image( destination 
coordinate) crosses the other screen.
+         * b) top and left coordinates of copied image( destination 
coordinate)  cross the other screen.
+        */
+        if( PanoramiXNumScreens > 1)
+        FOR_NSCREENS_BACKWARD(j) {
+              rc = dixLookupDrawable(drawables+j, src->info[j].id, 
client, 0,
+                   DixGetAttrAccess);
+        if (rc != Success)
+        return rc;
+            if(!((drawables[j]->width + drawables[j]->x) < 0 ||
+                (drawables[j]->height + drawables[j]->y) < 0 ||
+                ((stuff->srcX + drawables[j]->x + stuff->width) < 0 &&
+                (stuff->dstX + drawables[j]->x + stuff->width) < 0 )||
+                ((stuff->srcY + drawables[j]->y + stuff->height) < 0 &&
+                (stuff->dstY + drawables[j]->y + stuff->height) < 0 ) ||
+                ((drawables[j]->x + stuff->srcX) > 
drawables[j]->pScreen->width &&
+                (drawables[j]->x + stuff->dstX) > 
drawables[j]->pScreen->width ) ||
+                ((drawables[j]->y + stuff->srcY) > 
drawables[j]->pScreen->height &&
+                (drawables[j]->y + stuff->dstY) > 
drawables[j]->pScreen->height ))) {
+                if(!(stuff->srcX == stuff->dstX && (stuff->srcY + 
drawables[j]->y) > 0 &&
+                    (stuff->srcY + drawables[j]->y + stuff->height) 
<drawables[j]->pScreen->height) &&
+                   !(stuff->srcY == stuff->dstY && (stuff->srcX + 
drawables[j]->x) > 0 &&
+                    (stuff->srcX + drawables[j]->x + 
stuff->width)<drawables[j]->pScreen->width))
+                  cross_screen++;
+                }
+        }
+
+    /* if not cross screens, don't even bother calculatnge the overlap */
+    if(cross_screen > 1) {
+          RegionRec overlap, imageReg;
+          BoxRec imageBox;
+      FOR_NSCREENS_BACKWARD(j) {
+            stuff->dstDrawable = dst->info[j].id;
+            stuff->srcDrawable = src->info[j].id;
+            stuff->gc          = gc->info[j].id;
+            if (srcIsRoot) {
+                stuff->srcX = srcx - panoramiXdataPtr[j].x;
+                stuff->srcY = srcy - panoramiXdataPtr[j].y;
+            }
+            if (dstIsRoot) {
+                stuff->dstX = dstx - panoramiXdataPtr[j].x;
+                stuff->dstY = dsty - panoramiXdataPtr[j].y;
+            }
+
+            VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, 
DixWriteAccess);
+
+        if (stuff->dstDrawable != stuff->srcDrawable) {
+        rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0,
+                       DixReadAccess);
+        if (rc != Success)
+            return rc;
+
+        if ((pDst->pScreen != pSrc->pScreen) ||
+            (pDst->depth != pSrc->depth)) {
+            client->errorValue = stuff->dstDrawable;
+            return (BadMatch);
+                }
+            } else
+        pSrc = pDst;
+
+           /*  calculate the overlap area first and get the
+       image of the overlap area only */
+            pRgn[j] = getRgn(pSrc, pDst, pGC,
+                                stuff->srcX, stuff->srcY,
+                                stuff->width, stuff->height,
+                                stuff->dstX, stuff->dstY);
+            if(pRgn[j] && REGION_NOTEMPTY(pDst->pScreen, pRgn[j])) {
+                imageBox.x1 = dstx;
+                imageBox.y1 = dsty;
+                imageBox.x2 = dstx + stuff->width;
+                imageBox.y2 = dsty + stuff->height;
+
+                REGION_INIT(pDst->pScreen, &imageReg, &imageBox, 1);
+                REGION_INIT(pDst->pScreen, &overlap, NullBox, 1);
+                REGION_INTERSECT(pDst->pScreen, &overlap, &imageReg, 
pRgn[j]);
+
+                if (REGION_NOTEMPTY(pDst->pScreen, &overlap)) {
+            int i;
+            if(!rsrcFlag) {
+            rsrcx = rsrcy = 100000;
+            rsrcx2 = rsrcy2 = 0;
+            rsrcFlag = 1;
+            }
+            for (i = 0; i < REGION_NUM_RECTS(&overlap); i++) {
+                        BoxPtr rects = REGION_RECTS(&overlap);
+            if(rsrcx > (rects[i].x1 - dstx))
+                rsrcx = rects[i].x1 - dstx;
+            if(rsrcy > (rects[i].y1 - dsty))
+                rsrcy = rects[i].y1 - dsty;
+            if(rsrcx2 < (rects[i].x2 - dstx))
+                rsrcx2 =  rects[i].x2 - dstx;
+            if( rsrcy2 < (rects[i].y2 - dsty))
+                            rsrcy2 =  rects[i].y2 - dsty;
+                    }
+
+                    REGION_UNINIT(pDst->pScreen, &overlap);
+                    REGION_UNINIT(pDst->pScreen, &imageReg);
+              }
+            }
+      }
+      pitch = PixmapBytePad(stuff->width, drawables[0]->depth);
+      data_size = stuff->height * pitch;
+      if(!(data =  xcalloc(1,data_size)))
+            return BadAlloc;
+
+        /*  In Internal Xcopy  temporary buffer is allocattated and 
Xineramadata is copied .
+         *  Size of temporary buffer is same as drawing object(stuff).
+         *  GetImage reads the image(Xineramadata) from all 
intersection boxes.
+         *  When image overlaps between two or more screens, we can 
visualize portion of image in intersection boxes.
+         */
+
+      XineramaGetImageData(drawables, srcx+rsrcx, srcy+rsrcy,
+                  rsrcx2 - rsrcx, rsrcy2 - rsrcy, ZPixmap,
+                  ~0, data, pitch, srcIsRoot);
+    }
+
+    FOR_NSCREENS_BACKWARD(j) {
+        stuff->dstDrawable = dst->info[j].id;
+        stuff->srcDrawable = src->info[j].id;
+        stuff->gc          = gc->info[j].id;
+            if (srcIsRoot){
+        stuff->srcX = srcx - panoramiXdataPtr[j].x;
+        stuff->srcY = srcy - panoramiXdataPtr[j].y;
+        }
+            if (dstIsRoot){
+        stuff->dstX = dstx - panoramiXdataPtr[j].x;
+        stuff->dstY = dsty - panoramiXdataPtr[j].y;
+        }
+
+
+        VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess);
+
+        if (stuff->dstDrawable != stuff->srcDrawable) {
+        rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0,
+                       DixReadAccess);
+        if (rc != Success)
+            return rc;
+
+        if ((pDst->pScreen != pSrc->pScreen) ||
+            (pDst->depth != pSrc->depth)) {
+            client->errorValue = stuff->dstDrawable;
+            return (BadMatch);
+                }
+            } else
+        pSrc = pDst;
+
+        pRgn[j] = (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+                stuff->srcX, stuff->srcY,
+                stuff->width, stuff->height,
+                stuff->dstX, stuff->dstY);
+
+        if (cross_screen > 1 && pRgn[j] && 
REGION_NOTEMPTY(pDst->pScreen, pRgn[j])) {
+        RegionRec overlap, imageReg;
+        BoxRec imageBox;
+
+        if(drawables[0]->depth != pDst->depth) {
+            client->errorValue = stuff->dstDrawable;
+                    xfree(data );
+            return (BadMatch);
+        }
+
+        imageBox.x1 = dstx;
+        imageBox.y1 = dsty;
+        imageBox.x2 = dstx + stuff->width;
+        imageBox.y2 = dsty + stuff->height;
+
+        REGION_INIT(pDst->pScreen, &imageReg, &imageBox, 1);
+        REGION_INIT(pDst->pScreen, &overlap, NullBox, 1);
+        REGION_INTERSECT(pDst->pScreen, &overlap, &imageReg, pRgn[j]);
+
+        if (REGION_NOTEMPTY(pDst->pScreen, &overlap)) {
+            int i;
+            PixmapPtr pData;
+
+                    pData = GetScratchPixmapHeader(pDst->pScreen, 
rsrcx2-rsrcx,
+                    rsrcy2-rsrcy, pDst->depth, BitsPerPixel(pDst->depth),
+                    PixmapBytePad(rsrcx2-rsrcx, pDst->depth), data);
+
+            for (i = 0; i < REGION_NUM_RECTS(&overlap); i++) {
+            BoxPtr rects = REGION_RECTS(&overlap);
+            (*pGC->ops->CopyArea)((DrawablePtr) pData, pDst, pGC,
+              rects[i].x1 - dstx - rsrcx,
+              rects[i].y1 - dsty - rsrcy,
+              rects[i].x2 - rects[i].x1,
+              rects[i].y2 - rects[i].y1,
+              rects[i].x1, rects[i].y1);
+            }
+        }
+        REGION_UNINIT(pDst->pScreen, &overlap);
+        REGION_UNINIT(pDst->pScreen, &imageReg);
+        }
+    }
+
+    if(cross_screen > 1)
+            xfree(data);
+
+    result = Success;
     } else {
     DrawablePtr pDst = NULL, pSrc = NULL;
     GCPtr pGC = NULL;
-- 
1.5.6.5

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0001-Subject-PATCH-Xext-XCopyArea-does-not-work-in.patch
Url: http://lists.x.org/archives/xorg-devel/attachments/20091118/3b7027dd/attachment.ksh 


More information about the xorg-devel mailing list