Home | History | Annotate | Line # | Download | only in cw
      1 /*
      2  * Copyright  2004 Eric Anholt
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Eric Anholt not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Eric Anholt makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 #ifdef HAVE_DIX_CONFIG_H
     24 #include <dix-config.h>
     25 #endif
     26 
     27 #include <string.h>
     28 
     29 #include "gcstruct.h"
     30 #include "windowstr.h"
     31 #include "cw.h"
     32 
     33 #define CW_DEBUG 1
     34 
     35 #if CW_DEBUG
     36 #define CW_ASSERT(x) do {						\
     37     if (!(x)) {								\
     38 	ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \
     39 	    __LINE__);							\
     40     }									\
     41 } while (0)
     42 #else
     43 #define CW_ASSERT(x) do {} while (0)
     44 #endif
     45 
     46 DevPrivateKeyRec cwGCKeyRec;
     47 DevPrivateKeyRec cwScreenKeyRec;
     48 DevPrivateKeyRec cwWindowKeyRec;
     49 DevPrivateKeyRec cwPictureKeyRec;
     50 
     51 extern GCOps cwGCOps;
     52 
     53 static Bool
     54 cwCloseScreen (int i, ScreenPtr pScreen);
     55 
     56 static void
     57 cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable);
     58 static void
     59 cwChangeGC(GCPtr pGC, unsigned long mask);
     60 static void
     61 cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
     62 static void
     63 cwDestroyGC(GCPtr pGC);
     64 static void
     65 cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
     66 static void
     67 cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
     68 static void
     69 cwDestroyClip(GCPtr pGC);
     70 
     71 GCFuncs cwGCFuncs = {
     72     cwValidateGC,
     73     cwChangeGC,
     74     cwCopyGC,
     75     cwDestroyGC,
     76     cwChangeClip,
     77     cwDestroyClip,
     78     cwCopyClip,
     79 };
     80 
     81 /* Find the real drawable to draw to, and provide offsets that will translate
     82  * window coordinates to backing pixmap coordinates.
     83  */
     84 DrawablePtr
     85 cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off)
     86 {
     87     PixmapPtr	pPixmap;
     88 
     89     if (pDrawable->type == DRAWABLE_WINDOW &&
     90 	(pPixmap = getCwPixmap ((WindowPtr) pDrawable)))
     91     {
     92 	*x_off = pDrawable->x - pPixmap->screen_x;
     93 	*y_off = pDrawable->y - pPixmap->screen_y;
     94 	return &pPixmap->drawable;
     95     } else {
     96 	*x_off = *y_off = 0;
     97 	return pDrawable;
     98     }
     99 }
    100 
    101 #define FUNC_PROLOGUE(pGC, pPriv) do {					\
    102     (pGC)->funcs = (pPriv)->wrapFuncs;					\
    103     (pGC)->ops = (pPriv)->wrapOps;					\
    104 } while (0)
    105 
    106 #define FUNC_EPILOGUE(pGC, pPriv) do {					\
    107     (pPriv)->wrapFuncs = (pGC)->funcs;					\
    108     (pPriv)->wrapOps = (pGC)->ops;					\
    109     (pGC)->funcs = &cwGCFuncs;						\
    110     (pGC)->ops = &cwGCOps;						\
    111 } while (0)
    112 
    113 
    114 static Bool
    115 cwCreateBackingGC(GCPtr pGC, DrawablePtr pDrawable)
    116 {
    117     cwGCRec *pPriv = getCwGC(pGC);
    118     int status, x_off, y_off;
    119     XID noexpose = xFalse;
    120     DrawablePtr pBackingDrawable;
    121 
    122     pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
    123     pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures,
    124 				 &noexpose, &status, (XID)0, serverClient);
    125     if (status != Success)
    126 	return FALSE;
    127 
    128     pPriv->serialNumber = 0;
    129     pPriv->stateChanges = GCAllBits;
    130 
    131     return TRUE;
    132 }
    133 
    134 static void
    135 cwDestroyBackingGC(GCPtr pGC)
    136 {
    137     cwGCPtr pPriv;
    138 
    139     pPriv = (cwGCPtr) getCwGC (pGC);
    140 
    141     if (pPriv->pBackingGC) {
    142 	FreeGC(pPriv->pBackingGC, (XID)0);
    143 	pPriv->pBackingGC = NULL;
    144     }
    145 }
    146 
    147 static void
    148 cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable)
    149 {
    150     GCPtr   	  	pBackingGC;
    151     cwGCPtr		pPriv;
    152     DrawablePtr		pBackingDrawable;
    153     int			x_off, y_off;
    154 
    155     pPriv = (cwGCPtr) getCwGC (pGC);
    156 
    157     FUNC_PROLOGUE(pGC, pPriv);
    158 
    159     /*
    160      * Must call ValidateGC to ensure pGC->pCompositeClip is valid
    161      */
    162     (*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
    163 
    164     if (!cwDrawableIsRedirWindow(pDrawable)) {
    165 	cwDestroyBackingGC(pGC);
    166 	FUNC_EPILOGUE(pGC, pPriv);
    167 	return;
    168     } else {
    169 	if (!pPriv->pBackingGC && !cwCreateBackingGC(pGC, pDrawable)) {
    170 	    FUNC_EPILOGUE(pGC, pPriv);
    171 	    return;
    172 	}
    173     }
    174 
    175     pBackingGC = pPriv->pBackingGC;
    176     pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
    177 
    178     pPriv->stateChanges |= stateChanges;
    179 
    180     /*
    181      * Copy the composite clip into the backing GC if either
    182      * the drawable clip list has changed or the client has changed
    183      * the client clip data
    184      */
    185     if (pDrawable->serialNumber != pPriv->serialNumber ||
    186 	(pPriv->stateChanges & (GCClipXOrigin|GCClipYOrigin|GCClipMask)))
    187     {
    188 	ChangeGCVal vals[2];
    189 	RegionPtr   pCompositeClip;
    190 
    191 	pCompositeClip = RegionCreate(NULL, 0);
    192 	RegionCopy(pCompositeClip, pGC->pCompositeClip);
    193 
    194 	/* Either the drawable has changed, or the clip list in the drawable has
    195 	 * changed.  Copy the new clip list over and set the new translated
    196 	 * offset for it.
    197 	 */
    198 
    199 	(*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION,
    200 					  (pointer) pCompositeClip, 0);
    201 
    202 	vals[0].val = x_off - pDrawable->x;
    203 	vals[1].val = y_off - pDrawable->y;
    204 	ChangeGC(NullClient, pBackingGC,
    205 		    (GCClipXOrigin | GCClipYOrigin), vals);
    206 
    207 	pPriv->serialNumber = pDrawable->serialNumber;
    208 	/*
    209 	 * Mask off any client clip changes to make sure
    210 	 * the clip list set above remains in effect
    211 	 */
    212 	pPriv->stateChanges &= ~(GCClipXOrigin|GCClipYOrigin|GCClipMask);
    213     }
    214 
    215     if (pPriv->stateChanges) {
    216 	CopyGC(pGC, pBackingGC, pPriv->stateChanges);
    217 	pPriv->stateChanges = 0;
    218     }
    219 
    220     if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x ||
    221 	(pGC->patOrg.y + y_off) != pBackingGC->patOrg.y)
    222     {
    223 	ChangeGCVal vals[2];
    224 	vals[0].val = pGC->patOrg.x + x_off;
    225 	vals[1].val = pGC->patOrg.y + y_off;
    226 	ChangeGC(NullClient, pBackingGC,
    227 		    (GCTileStipXOrigin | GCTileStipYOrigin), vals);
    228     }
    229 
    230     ValidateGC(pBackingDrawable, pBackingGC);
    231 
    232     FUNC_EPILOGUE(pGC, pPriv);
    233 }
    234 
    235 static void
    236 cwChangeGC(GCPtr pGC, unsigned long mask)
    237 {
    238     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey);
    239 
    240     FUNC_PROLOGUE(pGC, pPriv);
    241 
    242     (*pGC->funcs->ChangeGC) (pGC, mask);
    243 
    244     FUNC_EPILOGUE(pGC, pPriv);
    245 }
    246 
    247 static void
    248 cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
    249 {
    250     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGCDst->devPrivates, cwGCKey);
    251 
    252     FUNC_PROLOGUE(pGCDst, pPriv);
    253 
    254     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
    255 
    256     FUNC_EPILOGUE(pGCDst, pPriv);
    257 }
    258 
    259 static void
    260 cwDestroyGC(GCPtr pGC)
    261 {
    262     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey);
    263 
    264     FUNC_PROLOGUE(pGC, pPriv);
    265 
    266     cwDestroyBackingGC(pGC);
    267 
    268     (*pGC->funcs->DestroyGC) (pGC);
    269 
    270     /* leave it unwrapped */
    271 }
    272 
    273 static void
    274 cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
    275 {
    276     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey);
    277 
    278     FUNC_PROLOGUE(pGC, pPriv);
    279 
    280     (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
    281 
    282     FUNC_EPILOGUE(pGC, pPriv);
    283 }
    284 
    285 static void
    286 cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
    287 {
    288     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pgcDst->devPrivates, cwGCKey);
    289 
    290     FUNC_PROLOGUE(pgcDst, pPriv);
    291 
    292     (*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
    293 
    294     FUNC_EPILOGUE(pgcDst, pPriv);
    295 }
    296 
    297 static void
    298 cwDestroyClip(GCPtr pGC)
    299 {
    300     cwGCPtr pPriv = (cwGCPtr)dixLookupPrivate(&pGC->devPrivates, cwGCKey);
    301 
    302     FUNC_PROLOGUE(pGC, pPriv);
    303 
    304     (*pGC->funcs->DestroyClip)(pGC);
    305 
    306     FUNC_EPILOGUE(pGC, pPriv);
    307 }
    308 
    309 /*
    310  * Screen wrappers.
    311  */
    312 
    313 #define SCREEN_PROLOGUE(pScreen, field)				\
    314   ((pScreen)->field = getCwScreen(pScreen)->field)
    315 
    316 #define SCREEN_EPILOGUE(pScreen, field, wrapper) do {		\
    317     getCwScreen(pScreen)->field = (pScreen)->field;		\
    318     (pScreen)->field = (wrapper);				\
    319 } while (0)
    320 
    321 static Bool
    322 cwCreateGC(GCPtr pGC)
    323 {
    324     cwGCPtr	pPriv = getCwGC(pGC);
    325     ScreenPtr	pScreen = pGC->pScreen;
    326     Bool	ret;
    327 
    328     SCREEN_PROLOGUE(pScreen, CreateGC);
    329 
    330     if ( (ret = (*pScreen->CreateGC)(pGC)) )
    331 	FUNC_EPILOGUE(pGC, pPriv);
    332 
    333     SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
    334 
    335     return ret;
    336 }
    337 
    338 static void
    339 cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format,
    340 	   unsigned long planemask, char *pdstLine)
    341 {
    342     ScreenPtr pScreen = pSrc->pScreen;
    343     DrawablePtr pBackingDrawable;
    344     int src_off_x, src_off_y;
    345 
    346     SCREEN_PROLOGUE(pScreen, GetImage);
    347 
    348     pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
    349 
    350     CW_OFFSET_XY_SRC(x, y);
    351 
    352     (*pScreen->GetImage)(pBackingDrawable, x, y, w, h, format, planemask,
    353 			 pdstLine);
    354 
    355     SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
    356 }
    357 
    358 static void
    359 cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth,
    360 	   int nspans, char *pdstStart)
    361 {
    362     ScreenPtr pScreen = pSrc->pScreen;
    363     DrawablePtr pBackingDrawable;
    364     int i;
    365     int src_off_x, src_off_y;
    366 
    367     SCREEN_PROLOGUE(pScreen, GetSpans);
    368 
    369     pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
    370 
    371     for (i = 0; i < nspans; i++)
    372 	CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y);
    373 
    374     (*pScreen->GetSpans)(pBackingDrawable, wMax, ppt, pwidth, nspans,
    375 			 pdstStart);
    376 
    377     SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
    378 }
    379 
    380 
    381 static void
    382 cwCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
    383 {
    384     ScreenPtr pScreen = pWin->drawable.pScreen;
    385 
    386     SCREEN_PROLOGUE(pScreen, CopyWindow);
    387 
    388     if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
    389 	(*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
    390     } else {
    391 	GCPtr	    pGC;
    392 	BoxPtr	    pExtents;
    393 	int	    x_off, y_off;
    394 	int	    dx, dy;
    395 	PixmapPtr   pBackingPixmap;
    396 	RegionPtr   pClip;
    397 	int	    src_x, src_y, dst_x, dst_y, w, h;
    398 
    399 	dx = ptOldOrg.x - pWin->drawable.x;
    400 	dy = ptOldOrg.y - pWin->drawable.y;
    401 
    402 	pExtents = RegionExtents(prgnSrc);
    403 
    404 	pBackingPixmap = (PixmapPtr) cwGetBackingDrawable((DrawablePtr)pWin,
    405 							  &x_off, &y_off);
    406 
    407 	src_x = pExtents->x1 - pBackingPixmap->screen_x;
    408 	src_y = pExtents->y1 - pBackingPixmap->screen_y;
    409 	w = pExtents->x2 - pExtents->x1;
    410 	h = pExtents->y2 - pExtents->y1;
    411 	dst_x = src_x - dx;
    412 	dst_y = src_y - dy;
    413 
    414 	/* Translate region (as required by API) */
    415 	RegionTranslate(prgnSrc, -dx, -dy);
    416 
    417 	pGC = GetScratchGC(pBackingPixmap->drawable.depth, pScreen);
    418 	/*
    419 	 * Copy region to GC as clip, aligning as dest clip
    420 	 */
    421 	pClip = RegionCreate(NULL, 0);
    422 	RegionIntersect(pClip, &pWin->borderClip, prgnSrc);
    423 	RegionTranslate(pClip,
    424 			 -pBackingPixmap->screen_x,
    425 			 -pBackingPixmap->screen_y);
    426 
    427 	(*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0);
    428 
    429 	ValidateGC(&pBackingPixmap->drawable, pGC);
    430 
    431 	(*pGC->ops->CopyArea) (&pBackingPixmap->drawable,
    432 			       &pBackingPixmap->drawable, pGC,
    433 			       src_x, src_y, w, h, dst_x, dst_y);
    434 
    435 	(*pGC->funcs->DestroyClip) (pGC);
    436 
    437 	FreeScratchGC(pGC);
    438     }
    439 
    440     SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
    441 }
    442 
    443 static PixmapPtr
    444 cwGetWindowPixmap (WindowPtr pWin)
    445 {
    446     PixmapPtr	pPixmap = getCwPixmap (pWin);
    447 
    448     if (!pPixmap)
    449     {
    450 	ScreenPtr   pScreen = pWin->drawable.pScreen;
    451 	SCREEN_PROLOGUE(pScreen, GetWindowPixmap);
    452 	if (pScreen->GetWindowPixmap)
    453 	    pPixmap = (*pScreen->GetWindowPixmap) (pWin);
    454 	SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
    455     }
    456     return pPixmap;
    457 }
    458 
    459 static void
    460 cwSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
    461 {
    462     ScreenPtr	pScreen = pWindow->drawable.pScreen;
    463 
    464     if (pPixmap == (*pScreen->GetScreenPixmap) (pScreen))
    465 	pPixmap = NULL;
    466     setCwPixmap (pWindow, pPixmap);
    467 }
    468 
    469 /* Screen initialization/teardown */
    470 void
    471 miInitializeCompositeWrapper(ScreenPtr pScreen)
    472 {
    473     cwScreenPtr pScreenPriv;
    474     Bool has_render = GetPictureScreenIfSet(pScreen) != NULL;
    475 
    476     if (!dixRegisterPrivateKey(&cwScreenKeyRec, PRIVATE_SCREEN, 0))
    477 	return;
    478 
    479     if (!dixRegisterPrivateKey(&cwGCKeyRec, PRIVATE_GC, sizeof(cwGCRec)))
    480 	return;
    481 
    482     if (!dixRegisterPrivateKey(&cwWindowKeyRec, PRIVATE_WINDOW, 0))
    483 	return;
    484 
    485     if (!dixRegisterPrivateKey(&cwPictureKeyRec, PRIVATE_PICTURE, 0))
    486 	return;
    487 
    488     pScreenPriv = malloc(sizeof(cwScreenRec));
    489     if (!pScreenPriv)
    490 	return;
    491 
    492     dixSetPrivate(&pScreen->devPrivates, cwScreenKey, pScreenPriv);
    493 
    494     SCREEN_EPILOGUE(pScreen, CloseScreen, cwCloseScreen);
    495     SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
    496     SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
    497     SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
    498     SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
    499 
    500     SCREEN_EPILOGUE(pScreen, SetWindowPixmap, cwSetWindowPixmap);
    501     SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
    502 
    503     if (has_render)
    504 	cwInitializeRender(pScreen);
    505 }
    506 
    507 static Bool
    508 cwCloseScreen (int i, ScreenPtr pScreen)
    509 {
    510     cwScreenPtr   pScreenPriv;
    511     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
    512 
    513     pScreenPriv = (cwScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
    514 						cwScreenKey);
    515     pScreen->CloseScreen = pScreenPriv->CloseScreen;
    516     pScreen->GetImage = pScreenPriv->GetImage;
    517     pScreen->GetSpans = pScreenPriv->GetSpans;
    518     pScreen->CreateGC = pScreenPriv->CreateGC;
    519     pScreen->CopyWindow = pScreenPriv->CopyWindow;
    520 
    521     if (ps)
    522 	cwFiniRender(pScreen);
    523 
    524     free((pointer)pScreenPriv);
    525 
    526     return (*pScreen->CloseScreen)(i, pScreen);
    527 }
    528