[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