pixmap.c revision 32414907
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 "site.h" 44#include "X11/extensions/render.h" 45#include "picturestr.h" 46#include "randrstr.h" 47/* 48 * Scratch pixmap management and device independent pixmap allocation 49 * function. 50 */ 51 52/* callable by ddx */ 53PixmapPtr 54GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth, 55 int bitsPerPixel, int devKind, void *pPixData) 56{ 57 PixmapPtr pPixmap = pScreen->pScratchPixmap; 58 59 if (pPixmap) 60 pScreen->pScratchPixmap = NULL; 61 else 62 /* width and height of 0 means don't allocate any pixmap data */ 63 pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); 64 65 if (pPixmap) { 66 if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, 67 bitsPerPixel, devKind, pPixData)) 68 return pPixmap; 69 (*pScreen->DestroyPixmap) (pPixmap); 70 } 71 return NullPixmap; 72} 73 74/* callable by ddx */ 75void 76FreeScratchPixmapHeader(PixmapPtr pPixmap) 77{ 78 if (pPixmap) { 79 ScreenPtr pScreen = pPixmap->drawable.pScreen; 80 81 pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */ 82 if (pScreen->pScratchPixmap) 83 (*pScreen->DestroyPixmap) (pPixmap); 84 else 85 pScreen->pScratchPixmap = pPixmap; 86 } 87} 88 89Bool 90CreateScratchPixmapsForScreen(ScreenPtr pScreen) 91{ 92 unsigned int pixmap_size; 93 94 pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP); 95 pScreen->totalPixmapSize = 96 BitmapBytePad(pixmap_size * 8); 97 98 /* let it be created on first use */ 99 pScreen->pScratchPixmap = NULL; 100 return TRUE; 101} 102 103void 104FreeScratchPixmapsForScreen(ScreenPtr pScreen) 105{ 106 FreeScratchPixmapHeader(pScreen->pScratchPixmap); 107} 108 109/* callable by ddx */ 110PixmapPtr 111AllocatePixmap(ScreenPtr pScreen, int pixDataSize) 112{ 113 PixmapPtr pPixmap; 114 115 assert(pScreen->totalPixmapSize > 0); 116 117 if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize) 118 return NullPixmap; 119 120 pPixmap = calloc(1, pScreen->totalPixmapSize + pixDataSize); 121 if (!pPixmap) 122 return NullPixmap; 123 124 dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP); 125 return pPixmap; 126} 127 128/* callable by ddx */ 129void 130FreePixmap(PixmapPtr pPixmap) 131{ 132 dixFiniPrivates(pPixmap, PRIVATE_PIXMAP); 133 free(pPixmap); 134} 135 136void PixmapUnshareSlavePixmap(PixmapPtr slave_pixmap) 137{ 138 int ihandle = -1; 139 ScreenPtr pScreen = slave_pixmap->drawable.pScreen; 140 pScreen->SetSharedPixmapBacking(slave_pixmap, ((void *)(long)ihandle)); 141} 142 143PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave) 144{ 145 PixmapPtr spix; 146 int ret; 147 void *handle; 148 ScreenPtr master = pixmap->drawable.pScreen; 149 int depth = pixmap->drawable.depth; 150 151 ret = master->SharePixmapBacking(pixmap, slave, &handle); 152 if (ret == FALSE) 153 return NULL; 154 155 spix = slave->CreatePixmap(slave, 0, 0, depth, 156 CREATE_PIXMAP_USAGE_SHARED); 157 slave->ModifyPixmapHeader(spix, pixmap->drawable.width, 158 pixmap->drawable.height, depth, 0, 159 pixmap->devKind, NULL); 160 161 /* have the slave pixmap take a reference on the master pixmap 162 later we destroy them both at the same time */ 163 pixmap->refcnt++; 164 165 spix->master_pixmap = pixmap; 166 167 ret = slave->SetSharedPixmapBacking(spix, handle); 168 if (ret == FALSE) { 169 slave->DestroyPixmap(spix); 170 return NULL; 171 } 172 173 return spix; 174} 175 176static void 177PixmapDirtyDamageDestroy(DamagePtr damage, void *closure) 178{ 179 PixmapDirtyUpdatePtr dirty = closure; 180 181 dirty->damage = NULL; 182} 183 184Bool 185PixmapStartDirtyTracking(DrawablePtr src, 186 PixmapPtr slave_dst, 187 int x, int y, int dst_x, int dst_y, 188 Rotation rotation) 189{ 190 ScreenPtr screen = src->pScreen; 191 PixmapDirtyUpdatePtr dirty_update; 192 RegionPtr damageregion; 193 RegionRec dstregion; 194 BoxRec box; 195 196 dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec)); 197 if (!dirty_update) 198 return FALSE; 199 200 dirty_update->src = src; 201 dirty_update->slave_dst = slave_dst; 202 dirty_update->x = x; 203 dirty_update->y = y; 204 dirty_update->dst_x = dst_x; 205 dirty_update->dst_y = dst_y; 206 dirty_update->rotation = rotation; 207 dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy, 208 DamageReportNone, TRUE, screen, 209 dirty_update); 210 211 if (rotation != RR_Rotate_0) { 212 RRTransformCompute(x, y, 213 slave_dst->drawable.width, 214 slave_dst->drawable.height, 215 rotation, 216 NULL, 217 &dirty_update->transform, 218 &dirty_update->f_transform, 219 &dirty_update->f_inverse); 220 } 221 if (!dirty_update->damage) { 222 free(dirty_update); 223 return FALSE; 224 } 225 226 /* Damage destination rectangle so that the destination pixmap contents 227 * will get fully initialized 228 */ 229 box.x1 = dirty_update->x; 230 box.y1 = dirty_update->y; 231 if (dirty_update->rotation == RR_Rotate_90 || 232 dirty_update->rotation == RR_Rotate_270) { 233 box.x2 = dirty_update->x + slave_dst->drawable.height; 234 box.y2 = dirty_update->y + slave_dst->drawable.width; 235 } else { 236 box.x2 = dirty_update->x + slave_dst->drawable.width; 237 box.y2 = dirty_update->y + slave_dst->drawable.height; 238 } 239 RegionInit(&dstregion, &box, 1); 240 damageregion = DamageRegion(dirty_update->damage); 241 RegionUnion(damageregion, damageregion, &dstregion); 242 RegionUninit(&dstregion); 243 244 DamageRegister(src, dirty_update->damage); 245 xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list); 246 return TRUE; 247} 248 249Bool 250PixmapStopDirtyTracking(DrawablePtr src, PixmapPtr slave_dst) 251{ 252 ScreenPtr screen = src->pScreen; 253 PixmapDirtyUpdatePtr ent, safe; 254 255 xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { 256 if (ent->src == src && ent->slave_dst == slave_dst) { 257 if (ent->damage) 258 DamageDestroy(ent->damage); 259 xorg_list_del(&ent->ent); 260 free(ent); 261 } 262 } 263 return TRUE; 264} 265 266static void 267PixmapDirtyCopyArea(PixmapPtr dst, 268 PixmapDirtyUpdatePtr dirty, 269 RegionPtr dirty_region) 270{ 271 DrawablePtr src = dirty->src; 272 ScreenPtr pScreen = src->pScreen; 273 int n; 274 BoxPtr b; 275 GCPtr pGC; 276 277 n = RegionNumRects(dirty_region); 278 b = RegionRects(dirty_region); 279 280 pGC = GetScratchGC(src->depth, pScreen); 281 if (pScreen->root) { 282 ChangeGCVal subWindowMode; 283 284 subWindowMode.val = IncludeInferiors; 285 ChangeGC(NullClient, pGC, GCSubwindowMode, &subWindowMode); 286 } 287 ValidateGC(&dst->drawable, pGC); 288 289 while (n--) { 290 BoxRec dst_box; 291 int w, h; 292 293 dst_box = *b; 294 w = dst_box.x2 - dst_box.x1; 295 h = dst_box.y2 - dst_box.y1; 296 297 pGC->ops->CopyArea(src, &dst->drawable, pGC, 298 dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, 299 dirty->dst_x + dst_box.x1, 300 dirty->dst_y + dst_box.y1); 301 b++; 302 } 303 FreeScratchGC(pGC); 304} 305 306static void 307PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap, 308 PixmapDirtyUpdatePtr dirty, 309 RegionPtr dirty_region) 310{ 311 ScreenPtr pScreen = dirty->src->pScreen; 312 PictFormatPtr format = PictureWindowFormat(pScreen->root); 313 PicturePtr src, dst; 314 XID include_inferiors = IncludeInferiors; 315 int n = RegionNumRects(dirty_region); 316 BoxPtr b = RegionRects(dirty_region); 317 int error; 318 319 src = CreatePicture(None, 320 dirty->src, 321 format, 322 CPSubwindowMode, 323 &include_inferiors, serverClient, &error); 324 if (!src) 325 return; 326 327 dst = CreatePicture(None, 328 &dst_pixmap->drawable, 329 format, 0L, NULL, serverClient, &error); 330 if (!dst) 331 return; 332 333 error = SetPictureTransform(src, &dirty->transform); 334 if (error) 335 return; 336 while (n--) { 337 BoxRec dst_box; 338 339 dst_box = *b; 340 dst_box.x1 += dirty->x; 341 dst_box.x2 += dirty->x; 342 dst_box.y1 += dirty->y; 343 dst_box.y2 += dirty->y; 344 pixman_f_transform_bounds(&dirty->f_inverse, &dst_box); 345 346 CompositePicture(PictOpSrc, 347 src, NULL, dst, 348 dst_box.x1, 349 dst_box.y1, 350 0, 0, 351 dst_box.x1, 352 dst_box.y1, 353 dst_box.x2 - dst_box.x1, 354 dst_box.y2 - dst_box.y1); 355 b++; 356 } 357 358 FreePicture(src, None); 359 FreePicture(dst, None); 360} 361 362/* 363 * this function can possibly be improved and optimised, by clipping 364 * instead of iterating 365 * Drivers are free to implement their own version of this. 366 */ 367Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty) 368{ 369 ScreenPtr pScreen = dirty->src->pScreen; 370 RegionPtr region = DamageRegion(dirty->damage); 371 PixmapPtr dst; 372 SourceValidateProcPtr SourceValidate; 373 RegionRec pixregion; 374 BoxRec box; 375 376 dst = dirty->slave_dst->master_pixmap; 377 if (!dst) 378 dst = dirty->slave_dst; 379 380 box.x1 = 0; 381 box.y1 = 0; 382 if (dirty->rotation == RR_Rotate_90 || 383 dirty->rotation == RR_Rotate_270) { 384 box.x2 = dst->drawable.height; 385 box.y2 = dst->drawable.width; 386 } else { 387 box.x2 = dst->drawable.width; 388 box.y2 = dst->drawable.height; 389 } 390 RegionInit(&pixregion, &box, 1); 391 392 /* 393 * SourceValidate is used by the software cursor code 394 * to pull the cursor off of the screen when reading 395 * bits from the frame buffer. Bypassing this function 396 * leaves the software cursor in place 397 */ 398 SourceValidate = pScreen->SourceValidate; 399 pScreen->SourceValidate = miSourceValidate; 400 401 RegionTranslate(&pixregion, dirty->x, dirty->y); 402 RegionIntersect(&pixregion, &pixregion, region); 403 404 if (RegionNil(&pixregion)) { 405 RegionUninit(&pixregion); 406 return FALSE; 407 } 408 409 RegionTranslate(&pixregion, -dirty->x, -dirty->y); 410 411 if (!pScreen->root || dirty->rotation == RR_Rotate_0) 412 PixmapDirtyCopyArea(dst, dirty, &pixregion); 413 else 414 PixmapDirtyCompositeRotate(dst, dirty, &pixregion); 415 pScreen->SourceValidate = SourceValidate; 416 return TRUE; 417} 418