[PATCH] Xext: XCopyArea() does not work in Xinerama. Bug#:25113
Arvind Umrao
Arvind.Umrao at Sun.COM
Fri Nov 27 03:14:15 PST 2009
Again request for review of patch attached in this email.
-Arvind
arvind Umrao wrote:
>
>
> 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;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Subject-PATCH-Xext-XCopyArea-does-not-work-in.patch
Type: text/x-patch
Size: 0 bytes
Desc: not available
Url : http://lists.x.org/archives/xorg-devel/attachments/20091127/8d3652bb/attachment-0001.bin
More information about the xorg-devel
mailing list