On Sat, Oct 15, 2011 at 2:27 AM, Arvind Umrao <[email protected]> wrote:
> 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.
>
> Signed-off-by: Arvind Umrao <[email protected]>
Some slight review below: fix those and I think it can have my
Reviewed-by tag added.
> }
>
> 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;
> + int cross_screen = 0, rsrcFlag = 0;
> + int rsrcx = 0, rsrcy = 0, rsrcx2 = stuff->width, rsrcy2 =
> stuff->height;
> +
> + bzero(pRgn, sizeof (RegionPtr) * MAXSCREENS);
memset instead of bzero please.
> +
> +
> + /*
> + * Execute only when Xinerama is on and having two or more screens.
> + * There are two cases when destination image will not lie in same
> sceen.
> + * a) Right and bottom coordinates of destination image crosses the
> + * other screen.
> + * b) Top and left coordinates of destination image 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++;
> + }
> + }
> + /*
> + * cross_screen > 1, signifies that there are more than one screens
> and
> + * source and destination image are not in the same screen.
> + */
> +
> + 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 - 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]);
> +
> + if (RegionNotEmpty(&overlap)) {
> + int i;
> + if (!rsrcFlag) {
> + rsrcx = rsrcy = 100000;
> + rsrcx2 = rsrcy2 = 0;
> + rsrcFlag = 1;
This deserves a decent comment ? what is 100,000 meant to signify?
> + }
> + /*
> + * This calculates the area of overlaping source image.
^ overlapping.
> + * There could be case when source image overlaps with
> two
> + * or more screens of Xinerama. RegionNumRects will
> return
> + * number of xinerama screens when source image overlaps
> and
> + * returns one when there is no overlap.
> + */
> +
> + 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 = xcalloc(1, data_size)))
> + return BadAlloc;
just use calloc now.
> +
> + /* 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)
> + return rc;
> +
> + if ((pDst->pScreen != pSrc->pScreen) ||
> + (pDst->depth != pSrc->depth)) {
> + client->errorValue = stuff->dstDrawable;
> + return (BadMatch);
> + }
> + } else
> + pSrc = pDst;
> +
> +
> + if (pRgn[j] && REGION_NOTEMPTY(pDst->pScreen, pRgn[j])) {
> +
> + if (drawables[0]->depth != pDst->depth) {
> + client->errorValue = stuff->dstDrawable;
> + xfree(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);
> + }
> + }
> + }
> + if (data)
> + xfree(data);
> +
> } else {
> DrawablePtr pDst = NULL, pSrc = NULL;
> GCPtr pGC = NULL;
> --
> 1.7.3.2
>
> _______________________________________________
> [email protected]: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
>
_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel