[PULL] Xext: XCopyArea does not work in Xinerama mode.#25113

Arvind Umrao arvind.umrao at oracle.com
Thu Nov 10 07:35:47 PST 2011


The following changes since commit 072ff17136b7c2d795d261870025c3061886b4c8:

  Xext: XCopyArea does not work in Xinerama mode.#25113 (2011-11-10 20:47:50 +0530)

are available in the git repository at:
  git://github.com/akumrao/xserver.git master

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=25113

XCopyArea() does not work in Xinerama mode. XCopyArea does not copy areas of the screen across physical displays. XcopyArea works fine when source and destination image are in same screen, but Xcopy does not work, when we Xcopy image from one screen to the other in Xinerama mode. The solution is to use internal Xcopy  instead of regular Xcopy. I mean use GetImage & PutImage Instead of regular Xcopy.

*1) Internal Xcopy*
In Internal Xcopy temporary buffer is allocated and Xineramadata is copied. GetImage reads the image(Xineramadata) from all intersection boxes and Putimage copies the image to the screen.

*2) Regular xcopy*
Regular xcopy calls the regular copyimage. Regular copyimage will be much faster when hardware acceleration is on.

Code changes are well commented. Code changes will execute only when xinerama is on and xcopy happens across screen. This bug was first reported for Xsun. Two years back, code changes was reviewed and intergrated to Oracle/Sun local Xserer repository.

*Testing*
a)I have tested it with Nvidia Quadro FX 1700 on x86 machine.You can find the test case in bugzilla. If you wish I can email some more test cases for stress testing.
b)I have tested my fixes using two XVR2500 frame buffer on SPARC Ultra 45 with Xinerama on. You can find the test case in bugzilla. If you wish I can email some more test cases, for stress testing.
c)Also I have tested my fixes on Sunray with Xinerama on

Reviewed-by: Dave Airlie <airlied at redhat.com>
2011BRB_Reviewed: Jeremy Huddleston <jeremyhu at freedesktop.org>
Signed-off-by: Arvind Umrao <arvind.umrao at oracle.com>
---
 Xext/panoramiXprocs.c |  215 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 215 insertions(+), 0 deletions(-)

diff --git a/Xext/panoramiXprocs.c b/Xext/panoramiXprocs.c
index 9ea4611..f8296e4 100644
--- a/Xext/panoramiXprocs.c
+++ b/Xext/panoramiXprocs.c
@@ -1074,6 +1074,221 @@ int PanoramiXCopyArea(ClientPtr client)
 	}
 
 	free(data);
+} else if (src->type == XRT_WINDOW) {
+        /*
+         * If destination image coordinate not lie in same screen of
+         * source image, then call Internal Copy instead of regular
+         * XCopy. I mean use GetImage & PutImage, instead of regular XCopy
+         */
+        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;
+        RegionRec overlap, imageReg;
+        BoxRec imageBox;
+        int cross_screen = 0, rsrcFlag = 0;
+        int rsrcx = 0, rsrcy = 0, rsrcx2 = stuff->width, rsrcy2 = stuff->height;
+
+        memset(pRgn, 0, sizeof(RegionPtr) * MAXSCREENS);
+
+        /*
+         * Execute only when Xinerama is on and having two or more screens.
+         * Two cases when source and dest. image will not lie in same screen.
+         * a) Right and bottom coordinates of destination image crosses the
+         * other screen.
+         * b) Top and left coordinates of destination image cross the other
+         * screen.
+         * Also check coordinates validity. Source and destination should
+         * not be same.
+         */
+        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++;
+            }
+        }
+        /*
+         * cross_screen > 1, signifies that there are more than one screens and
+         * source and destination image are not in the same screen.
+         */
+
+        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 - screenInfo.screens[j]->x;
+                stuff->srcY = srcy - screenInfo.screens[j]->y;
+            }
+            if (dstIsRoot) {
+                stuff->dstX = dstx - screenInfo.screens[j]->x;
+                stuff->dstY = dsty - screenInfo.screens[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 source and destination are not in same screen, instead of
+             * regular copy, use GetImage and PutImage
+             */
+
+            if (cross_screen > 1 && pRgn[j] && RegionNotEmpty(pRgn[j])) {
+                imageBox.x1 = stuff->srcX > 0 ? dstx : dstx - stuff->srcX;
+                imageBox.y1 = stuff->srcY > 0 ? dsty : dsty - stuff->srcY;
+                if (stuff->srcX + stuff->width > drawables[j]->width)
+                    imageBox.x2 = dstx - stuff->srcX + drawables[j]->width;
+                else
+                    imageBox.x2 = dstx + stuff->width;
+                if (stuff->srcY + stuff->height > drawables[j]->height)
+                    imageBox.y2 = dsty - stuff->srcY + drawables[j]->height;
+                else
+                    imageBox.y2 = dsty + stuff->height;
+
+                RegionInit(&imageReg, &imageBox, 1);
+                RegionInit(&overlap, NullBox, 1);
+                RegionIntersect(&overlap, &imageReg, pRgn[j]);
+
+                /* First initialize rsrcx & rsrcy to some very big number, impossible screen width.
+                 * There could be case when source image overlaps with two or more screens of Xinerama.
+                 * So calculates the area of overlapping source image.
+                 * RegionNumRects will return number of xinerama screens when source image overlaps and
+                 * returns one when there is no overlap. Suppose screen1(0,0,100,100), screen2(100,0,200,100)
+                 * & source image(80,0,130,50) then rsrcx2-rsrcx is 20 for screen1 and 30 for screen2.
+                 */
+                if (RegionNotEmpty(&overlap)) {
+                    int i;
+                    if (!rsrcFlag) {
+                        rsrcx = rsrcy = MAXINT;
+                        rsrcx2 = rsrcy2 = 0;
+                        rsrcFlag = 1;
+                    }
+
+                    for (i = 0; i < RegionNumRects(&overlap); i++) {
+                        BoxPtr rects = RegionRects(&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;
+                    }
+
+                    RegionUninit(&overlap);
+                    RegionUninit(&imageReg);
+                }
+            }
+        }
+
+        if (cross_screen > 1) {
+            pitch = PixmapBytePad(stuff->width, drawables[0]->depth);
+            data_size = stuff->height * pitch;
+            if (!(data = calloc(1, data_size)))
+                return BadAlloc;
+
+            /* Data which is not copied by regular XCopy, for that temporary
+             * buffer is allocatted and Xinerama data is copied. GetImage reads
+             * the image(Xineramadata) from all the intersection boxes.
+             * When image overlaps between two or more screens, we can visualize
+             * the 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 - screenInfo.screens[j]->x;
+                    stuff->srcY = srcy - screenInfo.screens[j]->y;
+                }
+                if (dstIsRoot) {
+                    stuff->dstX = dstx - screenInfo.screens[j]->x;
+                    stuff->dstY = dsty - screenInfo.screens[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) {
+                        free(data);
+                        return rc;
+                    }
+
+                    if ((pDst->pScreen != pSrc->pScreen) ||
+                            (pDst->depth != pSrc->depth)) {
+                        client->errorValue = stuff->dstDrawable;
+                        free(data);
+                        return (BadMatch);
+                    }
+                } else
+                    pSrc = pDst;
+
+                if (pRgn[j] && REGION_NOTEMPTY(pDst->pScreen, pRgn[j])) {
+
+                    if (drawables[0]->depth != pDst->depth) {
+                        client->errorValue = stuff->dstDrawable;
+                        free(data);
+                        return (BadMatch);
+                    }
+
+                    /*
+                     * Copy the buffered Xinerama data to screen
+                     */
+
+                    (*pGC->ops->PutImage) (pDst, pGC, pDst->depth, dstx + rsrcx, dsty + rsrcy,
+                            rsrcx2 - rsrcx, rsrcy2 - rsrcy, 0, ZPixmap, data);
+                }
+            }
+
+            free(data);
+        }
+
     } else {
 	DrawablePtr pDst = NULL, pSrc = NULL;
 	GCPtr pGC = NULL;
-- 
1.7.3.2



More information about the xorg-devel mailing list