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 46DevPrivateKeyRec cwGCKeyRec; 47DevPrivateKeyRec cwScreenKeyRec; 48DevPrivateKeyRec cwWindowKeyRec; 49DevPrivateKeyRec cwPictureKeyRec; 50 51extern GCOps cwGCOps; 52 53static Bool 54cwCloseScreen (int i, ScreenPtr pScreen); 55 56static void 57cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable); 58static void 59cwChangeGC(GCPtr pGC, unsigned long mask); 60static void 61cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); 62static void 63cwDestroyGC(GCPtr pGC); 64static void 65cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); 66static void 67cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc); 68static void 69cwDestroyClip(GCPtr pGC); 70 71GCFuncs 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 */ 84DrawablePtr 85cwGetBackingDrawable(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 114static Bool 115cwCreateBackingGC(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 134static void 135cwDestroyBackingGC(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 147static void 148cwValidateGC(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 235static void 236cwChangeGC(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 247static void 248cwCopyGC(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 259static void 260cwDestroyGC(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 273static void 274cwChangeClip(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 285static void 286cwCopyClip(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 297static void 298cwDestroyClip(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 321static Bool 322cwCreateGC(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 338static void 339cwGetImage(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 358static void 359cwGetSpans(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 381static void 382cwCopyWindow(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 443static PixmapPtr 444cwGetWindowPixmap (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 459static void 460cwSetWindowPixmap (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 */ 470void 471miInitializeCompositeWrapper(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 507static Bool 508cwCloseScreen (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