pixmap.c revision 35c4bbdf
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 "misc.h" 36#include "os.h" 37#include "windowstr.h" 38#include "resource.h" 39#include "dixstruct.h" 40#include "gcstruct.h" 41#include "servermd.h" 42#include "site.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 = malloc(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 135PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave) 136{ 137 PixmapPtr spix; 138 int ret; 139 void *handle; 140 ScreenPtr master = pixmap->drawable.pScreen; 141 int depth = pixmap->drawable.depth; 142 143 ret = master->SharePixmapBacking(pixmap, slave, &handle); 144 if (ret == FALSE) 145 return NULL; 146 147 spix = slave->CreatePixmap(slave, 0, 0, depth, 148 CREATE_PIXMAP_USAGE_SHARED); 149 slave->ModifyPixmapHeader(spix, pixmap->drawable.width, 150 pixmap->drawable.height, depth, 0, 151 pixmap->devKind, NULL); 152 153 /* have the slave pixmap take a reference on the master pixmap 154 later we destroy them both at the same time */ 155 pixmap->refcnt++; 156 157 spix->master_pixmap = pixmap; 158 159 ret = slave->SetSharedPixmapBacking(spix, handle); 160 if (ret == FALSE) { 161 slave->DestroyPixmap(spix); 162 return NULL; 163 } 164 165 return spix; 166} 167 168Bool 169PixmapStartDirtyTracking(PixmapPtr src, 170 PixmapPtr slave_dst, 171 int x, int y, int dst_x, int dst_y, 172 Rotation rotation) 173{ 174 ScreenPtr screen = src->drawable.pScreen; 175 PixmapDirtyUpdatePtr dirty_update; 176 RegionPtr damageregion; 177 RegionRec dstregion; 178 BoxRec box; 179 180 dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec)); 181 if (!dirty_update) 182 return FALSE; 183 184 dirty_update->src = src; 185 dirty_update->slave_dst = slave_dst; 186 dirty_update->x = x; 187 dirty_update->y = y; 188 dirty_update->dst_x = dst_x; 189 dirty_update->dst_y = dst_y; 190 dirty_update->rotation = rotation; 191 dirty_update->damage = DamageCreate(NULL, NULL, 192 DamageReportNone, 193 TRUE, src->drawable.pScreen, 194 src->drawable.pScreen); 195 196 if (rotation != RR_Rotate_0) { 197 RRTransformCompute(x, y, 198 slave_dst->drawable.width, 199 slave_dst->drawable.height, 200 rotation, 201 NULL, 202 &dirty_update->transform, 203 &dirty_update->f_transform, 204 &dirty_update->f_inverse); 205 } 206 if (!dirty_update->damage) { 207 free(dirty_update); 208 return FALSE; 209 } 210 211 /* Damage destination rectangle so that the destination pixmap contents 212 * will get fully initialized 213 */ 214 box.x1 = dirty_update->x; 215 box.y1 = dirty_update->y; 216 if (dirty_update->rotation == RR_Rotate_90 || 217 dirty_update->rotation == RR_Rotate_270) { 218 box.x2 = dirty_update->x + slave_dst->drawable.height; 219 box.y2 = dirty_update->y + slave_dst->drawable.width; 220 } else { 221 box.x2 = dirty_update->x + slave_dst->drawable.width; 222 box.y2 = dirty_update->y + slave_dst->drawable.height; 223 } 224 RegionInit(&dstregion, &box, 1); 225 damageregion = DamageRegion(dirty_update->damage); 226 RegionUnion(damageregion, damageregion, &dstregion); 227 RegionUninit(&dstregion); 228 229 DamageRegister(&src->drawable, dirty_update->damage); 230 xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list); 231 return TRUE; 232} 233 234Bool 235PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst) 236{ 237 ScreenPtr screen = src->drawable.pScreen; 238 PixmapDirtyUpdatePtr ent, safe; 239 240 xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { 241 if (ent->src == src && ent->slave_dst == slave_dst) { 242 DamageDestroy(ent->damage); 243 xorg_list_del(&ent->ent); 244 free(ent); 245 } 246 } 247 return TRUE; 248} 249 250static void 251PixmapDirtyCopyArea(PixmapPtr dst, 252 PixmapDirtyUpdatePtr dirty, 253 RegionPtr dirty_region) 254{ 255 ScreenPtr pScreen = dirty->src->drawable.pScreen; 256 int n; 257 BoxPtr b; 258 GCPtr pGC; 259 260 n = RegionNumRects(dirty_region); 261 b = RegionRects(dirty_region); 262 263 pGC = GetScratchGC(dirty->src->drawable.depth, pScreen); 264 ValidateGC(&dst->drawable, pGC); 265 266 while (n--) { 267 BoxRec dst_box; 268 int w, h; 269 270 dst_box = *b; 271 w = dst_box.x2 - dst_box.x1; 272 h = dst_box.y2 - dst_box.y1; 273 274 pGC->ops->CopyArea(&dirty->src->drawable, &dst->drawable, pGC, 275 dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, 276 dirty->dst_x + dst_box.x1, 277 dirty->dst_y + dst_box.y1); 278 b++; 279 } 280 FreeScratchGC(pGC); 281} 282 283static void 284PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap, 285 PixmapDirtyUpdatePtr dirty, 286 RegionPtr dirty_region) 287{ 288 ScreenPtr pScreen = dirty->src->drawable.pScreen; 289 PictFormatPtr format = PictureWindowFormat(pScreen->root); 290 PicturePtr src, dst; 291 XID include_inferiors = IncludeInferiors; 292 int n = RegionNumRects(dirty_region); 293 BoxPtr b = RegionRects(dirty_region); 294 int error; 295 296 src = CreatePicture(None, 297 &dirty->src->drawable, 298 format, 299 CPSubwindowMode, 300 &include_inferiors, serverClient, &error); 301 if (!src) 302 return; 303 304 dst = CreatePicture(None, 305 &dst_pixmap->drawable, 306 format, 0L, NULL, serverClient, &error); 307 if (!dst) 308 return; 309 310 error = SetPictureTransform(src, &dirty->transform); 311 if (error) 312 return; 313 while (n--) { 314 BoxRec dst_box; 315 316 dst_box = *b; 317 dst_box.x1 += dirty->x; 318 dst_box.x2 += dirty->x; 319 dst_box.y1 += dirty->y; 320 dst_box.y2 += dirty->y; 321 pixman_f_transform_bounds(&dirty->f_inverse, &dst_box); 322 323 CompositePicture(PictOpSrc, 324 src, NULL, dst, 325 dst_box.x1, 326 dst_box.y1, 327 0, 0, 328 dst_box.x1, 329 dst_box.y1, 330 dst_box.x2 - dst_box.x1, 331 dst_box.y2 - dst_box.y1); 332 b++; 333 } 334 335 FreePicture(src, None); 336 FreePicture(dst, None); 337} 338 339/* 340 * this function can possibly be improved and optimised, by clipping 341 * instead of iterating 342 * Drivers are free to implement their own version of this. 343 */ 344Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty) 345{ 346 ScreenPtr pScreen = dirty->src->drawable.pScreen; 347 RegionPtr region = DamageRegion(dirty->damage); 348 PixmapPtr dst; 349 SourceValidateProcPtr SourceValidate; 350 RegionRec pixregion; 351 BoxRec box; 352 353 dst = dirty->slave_dst->master_pixmap; 354 if (!dst) 355 dst = dirty->slave_dst; 356 357 box.x1 = 0; 358 box.y1 = 0; 359 if (dirty->rotation == RR_Rotate_90 || 360 dirty->rotation == RR_Rotate_270) { 361 box.x2 = dst->drawable.height; 362 box.y2 = dst->drawable.width; 363 } else { 364 box.x2 = dst->drawable.width; 365 box.y2 = dst->drawable.height; 366 } 367 RegionInit(&pixregion, &box, 1); 368 369 /* 370 * SourceValidate is used by the software cursor code 371 * to pull the cursor off of the screen when reading 372 * bits from the frame buffer. Bypassing this function 373 * leaves the software cursor in place 374 */ 375 SourceValidate = pScreen->SourceValidate; 376 pScreen->SourceValidate = NULL; 377 378 RegionTranslate(&pixregion, dirty->x, dirty->y); 379 RegionIntersect(&pixregion, &pixregion, region); 380 381 if (RegionNil(&pixregion)) { 382 RegionUninit(&pixregion); 383 return FALSE; 384 } 385 386 RegionTranslate(&pixregion, -dirty->x, -dirty->y); 387 388 if (!pScreen->root || dirty->rotation == RR_Rotate_0) 389 PixmapDirtyCopyArea(dst, dirty, &pixregion); 390 else 391 PixmapDirtyCompositeRotate(dst, dirty, &pixregion); 392 pScreen->SourceValidate = SourceValidate; 393 return TRUE; 394} 395