1/* 2 3Copyright 1993, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28 29#ifdef HAVE_DIX_CONFIG_H 30#include <dix-config.h> 31#endif 32 33#include <X11/X.h> 34#include "scrnintstr.h" 35#include "mi.h" 36#include "misc.h" 37#include "os.h" 38#include "windowstr.h" 39#include "resource.h" 40#include "dixstruct.h" 41#include "gcstruct.h" 42#include "servermd.h" 43#include "X11/extensions/render.h" 44#include "picturestr.h" 45#include "randrstr.h" 46/* 47 * Scratch pixmap management and device independent pixmap allocation 48 * function. 49 */ 50 51/* callable by ddx */ 52PixmapPtr 53GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth, 54 int bitsPerPixel, int devKind, void *pPixData) 55{ 56 PixmapPtr pPixmap = pScreen->pScratchPixmap; 57 58 if (pPixmap) 59 pScreen->pScratchPixmap = NULL; 60 else 61 /* width and height of 0 means don't allocate any pixmap data */ 62 pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); 63 64 if (pPixmap) { 65 if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, 66 bitsPerPixel, devKind, pPixData)) 67 return pPixmap; 68 (*pScreen->DestroyPixmap) (pPixmap); 69 } 70 return NullPixmap; 71} 72 73/* callable by ddx */ 74void 75FreeScratchPixmapHeader(PixmapPtr pPixmap) 76{ 77 if (pPixmap) { 78 ScreenPtr pScreen = pPixmap->drawable.pScreen; 79 80 pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */ 81 if (pScreen->pScratchPixmap) 82 (*pScreen->DestroyPixmap) (pPixmap); 83 else 84 pScreen->pScratchPixmap = pPixmap; 85 } 86} 87 88Bool 89CreateScratchPixmapsForScreen(ScreenPtr pScreen) 90{ 91 unsigned int pixmap_size; 92 93 pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP); 94 pScreen->totalPixmapSize = 95 BitmapBytePad(pixmap_size * 8); 96 97 /* let it be created on first use */ 98 pScreen->pScratchPixmap = NULL; 99 return TRUE; 100} 101 102void 103FreeScratchPixmapsForScreen(ScreenPtr pScreen) 104{ 105 FreeScratchPixmapHeader(pScreen->pScratchPixmap); 106} 107 108/* callable by ddx */ 109PixmapPtr 110AllocatePixmap(ScreenPtr pScreen, int pixDataSize) 111{ 112 PixmapPtr pPixmap; 113 114 assert(pScreen->totalPixmapSize > 0); 115 116 if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize) 117 return NullPixmap; 118 119 pPixmap = calloc(1, pScreen->totalPixmapSize + pixDataSize); 120 if (!pPixmap) 121 return NullPixmap; 122 123 dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP); 124 return pPixmap; 125} 126 127/* callable by ddx */ 128void 129FreePixmap(PixmapPtr pPixmap) 130{ 131 dixFiniPrivates(pPixmap, PRIVATE_PIXMAP); 132 free(pPixmap); 133} 134 135void PixmapUnshareSecondaryPixmap(PixmapPtr secondary_pixmap) 136{ 137 int ihandle = -1; 138 ScreenPtr pScreen = secondary_pixmap->drawable.pScreen; 139 pScreen->SetSharedPixmapBacking(secondary_pixmap, ((void *)(long)ihandle)); 140} 141 142PixmapPtr PixmapShareToSecondary(PixmapPtr pixmap, ScreenPtr secondary) 143{ 144 PixmapPtr spix; 145 int ret; 146 void *handle; 147 ScreenPtr primary = pixmap->drawable.pScreen; 148 int depth = pixmap->drawable.depth; 149 150 ret = primary->SharePixmapBacking(pixmap, secondary, &handle); 151 if (ret == FALSE) 152 return NULL; 153 154 spix = secondary->CreatePixmap(secondary, 0, 0, depth, 155 CREATE_PIXMAP_USAGE_SHARED); 156 secondary->ModifyPixmapHeader(spix, pixmap->drawable.width, 157 pixmap->drawable.height, depth, 0, 158 pixmap->devKind, NULL); 159 160 /* have the secondary pixmap take a reference on the primary pixmap 161 later we destroy them both at the same time */ 162 pixmap->refcnt++; 163 164 spix->primary_pixmap = pixmap; 165 166 ret = secondary->SetSharedPixmapBacking(spix, handle); 167 if (ret == FALSE) { 168 secondary->DestroyPixmap(spix); 169 return NULL; 170 } 171 172 return spix; 173} 174 175static void 176PixmapDirtyDamageDestroy(DamagePtr damage, void *closure) 177{ 178 PixmapDirtyUpdatePtr dirty = closure; 179 180 dirty->damage = NULL; 181} 182 183Bool 184PixmapStartDirtyTracking(DrawablePtr src, 185 PixmapPtr secondary_dst, 186 int x, int y, int dst_x, int dst_y, 187 Rotation rotation) 188{ 189 ScreenPtr screen = src->pScreen; 190 PixmapDirtyUpdatePtr dirty_update; 191 RegionPtr damageregion; 192 RegionRec dstregion; 193 BoxRec box; 194 195 dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec)); 196 if (!dirty_update) 197 return FALSE; 198 199 dirty_update->src = src; 200 dirty_update->secondary_dst = secondary_dst; 201 dirty_update->x = x; 202 dirty_update->y = y; 203 dirty_update->dst_x = dst_x; 204 dirty_update->dst_y = dst_y; 205 dirty_update->rotation = rotation; 206 dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy, 207 DamageReportNone, TRUE, screen, 208 dirty_update); 209 210 if (rotation != RR_Rotate_0) { 211 RRTransformCompute(x, y, 212 secondary_dst->drawable.width, 213 secondary_dst->drawable.height, 214 rotation, 215 NULL, 216 &dirty_update->transform, 217 &dirty_update->f_transform, 218 &dirty_update->f_inverse); 219 } 220 if (!dirty_update->damage) { 221 free(dirty_update); 222 return FALSE; 223 } 224 225 /* Damage destination rectangle so that the destination pixmap contents 226 * will get fully initialized 227 */ 228 box.x1 = dirty_update->x; 229 box.y1 = dirty_update->y; 230 if (dirty_update->rotation == RR_Rotate_90 || 231 dirty_update->rotation == RR_Rotate_270) { 232 box.x2 = dirty_update->x + secondary_dst->drawable.height; 233 box.y2 = dirty_update->y + secondary_dst->drawable.width; 234 } else { 235 box.x2 = dirty_update->x + secondary_dst->drawable.width; 236 box.y2 = dirty_update->y + secondary_dst->drawable.height; 237 } 238 RegionInit(&dstregion, &box, 1); 239 damageregion = DamageRegion(dirty_update->damage); 240 RegionUnion(damageregion, damageregion, &dstregion); 241 RegionUninit(&dstregion); 242 243 DamageRegister(src, dirty_update->damage); 244 xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list); 245 return TRUE; 246} 247 248Bool 249PixmapStopDirtyTracking(DrawablePtr src, PixmapPtr secondary_dst) 250{ 251 ScreenPtr screen = src->pScreen; 252 PixmapDirtyUpdatePtr ent, safe; 253 254 xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { 255 if (ent->src == src && ent->secondary_dst == secondary_dst) { 256 if (ent->damage) 257 DamageDestroy(ent->damage); 258 xorg_list_del(&ent->ent); 259 free(ent); 260 } 261 } 262 return TRUE; 263} 264 265static void 266PixmapDirtyCopyArea(PixmapPtr dst, 267 PixmapDirtyUpdatePtr dirty, 268 RegionPtr dirty_region) 269{ 270 DrawablePtr src = dirty->src; 271 ScreenPtr pScreen = src->pScreen; 272 int n; 273 BoxPtr b; 274 GCPtr pGC; 275 276 n = RegionNumRects(dirty_region); 277 b = RegionRects(dirty_region); 278 279 pGC = GetScratchGC(src->depth, pScreen); 280 if (pScreen->root) { 281 ChangeGCVal subWindowMode; 282 283 subWindowMode.val = IncludeInferiors; 284 ChangeGC(NullClient, pGC, GCSubwindowMode, &subWindowMode); 285 } 286 ValidateGC(&dst->drawable, pGC); 287 288 while (n--) { 289 BoxRec dst_box; 290 int w, h; 291 292 dst_box = *b; 293 w = dst_box.x2 - dst_box.x1; 294 h = dst_box.y2 - dst_box.y1; 295 296 pGC->ops->CopyArea(src, &dst->drawable, pGC, 297 dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, 298 dirty->dst_x + dst_box.x1, 299 dirty->dst_y + dst_box.y1); 300 b++; 301 } 302 FreeScratchGC(pGC); 303} 304 305static void 306PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap, 307 PixmapDirtyUpdatePtr dirty, 308 RegionPtr dirty_region) 309{ 310 ScreenPtr pScreen = dirty->src->pScreen; 311 PictFormatPtr format = PictureWindowFormat(pScreen->root); 312 PicturePtr src, dst; 313 XID include_inferiors = IncludeInferiors; 314 int n = RegionNumRects(dirty_region); 315 BoxPtr b = RegionRects(dirty_region); 316 int error; 317 318 src = CreatePicture(None, 319 dirty->src, 320 format, 321 CPSubwindowMode, 322 &include_inferiors, serverClient, &error); 323 if (!src) 324 return; 325 326 dst = CreatePicture(None, 327 &dst_pixmap->drawable, 328 format, 0L, NULL, serverClient, &error); 329 if (!dst) 330 return; 331 332 error = SetPictureTransform(src, &dirty->transform); 333 if (error) 334 return; 335 while (n--) { 336 BoxRec dst_box; 337 338 dst_box = *b; 339 dst_box.x1 += dirty->x; 340 dst_box.x2 += dirty->x; 341 dst_box.y1 += dirty->y; 342 dst_box.y2 += dirty->y; 343 pixman_f_transform_bounds(&dirty->f_inverse, &dst_box); 344 345 CompositePicture(PictOpSrc, 346 src, NULL, dst, 347 dst_box.x1, 348 dst_box.y1, 349 0, 0, 350 dst_box.x1, 351 dst_box.y1, 352 dst_box.x2 - dst_box.x1, 353 dst_box.y2 - dst_box.y1); 354 b++; 355 } 356 357 FreePicture(src, None); 358 FreePicture(dst, None); 359} 360 361/* 362 * this function can possibly be improved and optimised, by clipping 363 * instead of iterating 364 * Drivers are free to implement their own version of this. 365 */ 366Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty) 367{ 368 ScreenPtr pScreen = dirty->src->pScreen; 369 RegionPtr region = DamageRegion(dirty->damage); 370 PixmapPtr dst; 371 SourceValidateProcPtr SourceValidate; 372 RegionRec pixregion; 373 BoxRec box; 374 375 dst = dirty->secondary_dst->primary_pixmap; 376 if (!dst) 377 dst = dirty->secondary_dst; 378 379 box.x1 = 0; 380 box.y1 = 0; 381 if (dirty->rotation == RR_Rotate_90 || 382 dirty->rotation == RR_Rotate_270) { 383 box.x2 = dst->drawable.height; 384 box.y2 = dst->drawable.width; 385 } else { 386 box.x2 = dst->drawable.width; 387 box.y2 = dst->drawable.height; 388 } 389 RegionInit(&pixregion, &box, 1); 390 391 /* 392 * SourceValidate is used by the software cursor code 393 * to pull the cursor off of the screen when reading 394 * bits from the frame buffer. Bypassing this function 395 * leaves the software cursor in place 396 */ 397 SourceValidate = pScreen->SourceValidate; 398 pScreen->SourceValidate = miSourceValidate; 399 400 RegionTranslate(&pixregion, dirty->x, dirty->y); 401 RegionIntersect(&pixregion, &pixregion, region); 402 403 if (RegionNil(&pixregion)) { 404 RegionUninit(&pixregion); 405 return FALSE; 406 } 407 408 RegionTranslate(&pixregion, -dirty->x, -dirty->y); 409 410 if (!pScreen->root || dirty->rotation == RR_Rotate_0) 411 PixmapDirtyCopyArea(dst, dirty, &pixregion); 412 else 413 PixmapDirtyCompositeRotate(dst, dirty, &pixregion); 414 pScreen->SourceValidate = SourceValidate; 415 return TRUE; 416} 417