| 1 | /* |
| 2 | |
| 3 | Copyright 1993, 1998 The Open Group |
| 4 | |
| 5 | Permission to use, copy, modify, distribute, and sell this software and its |
| 6 | documentation for any purpose is hereby granted without fee, provided that |
| 7 | the above copyright notice appear in all copies and that both that |
| 8 | copyright notice and this permission notice appear in supporting |
| 9 | documentation. |
| 10 | |
| 11 | The above copyright notice and this permission notice shall be included |
| 12 | in all copies or substantial portions of the Software. |
| 13 | |
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 20 | OTHER DEALINGS IN THE SOFTWARE. |
| 21 | |
| 22 | Except as contained in this notice, the name of The Open Group shall |
| 23 | not be used in advertising or otherwise to promote the sale, use or |
| 24 | other dealings in this Software without prior written authorization |
| 25 | from 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 | |
| 44 | /* |
| 45 | * Scratch pixmap management and device independent pixmap allocation |
| 46 | * function. |
| 47 | */ |
| 48 | |
| 49 | /* callable by ddx */ |
| 50 | PixmapPtr |
| 51 | GetScratchPixmapHeader(ScreenPtr pScreen, int width, int height, int depth, |
| 52 | int bitsPerPixel, int devKind, pointer pPixData) |
| 53 | { |
| 54 | PixmapPtr pPixmap = pScreen->pScratchPixmap; |
| 55 | |
| 56 | if (pPixmap) |
| 57 | pScreen->pScratchPixmap = NULL; |
| 58 | else |
| 59 | /* width and height of 0 means don't allocate any pixmap data */ |
| 60 | pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); |
| 61 | |
| 62 | if (pPixmap) { |
| 63 | if ((*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, |
| 64 | bitsPerPixel, devKind, pPixData)) |
| 65 | return pPixmap; |
| 66 | (*pScreen->DestroyPixmap) (pPixmap); |
| 67 | } |
| 68 | return NullPixmap; |
| 69 | } |
| 70 | |
| 71 | /* callable by ddx */ |
| 72 | void |
| 73 | FreeScratchPixmapHeader(PixmapPtr pPixmap) |
| 74 | { |
| 75 | if (pPixmap) { |
| 76 | ScreenPtr pScreen = pPixmap->drawable.pScreen; |
| 77 | |
| 78 | pPixmap->devPrivate.ptr = NULL; /* lest ddx chases bad ptr */ |
| 79 | if (pScreen->pScratchPixmap) |
| 80 | (*pScreen->DestroyPixmap) (pPixmap); |
| 81 | else |
| 82 | pScreen->pScratchPixmap = pPixmap; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | Bool |
| 87 | CreateScratchPixmapsForScreen(ScreenPtr pScreen) |
| 88 | { |
| 89 | unsigned int pixmap_size; |
| 90 | |
| 91 | pixmap_size = sizeof(PixmapRec) + dixScreenSpecificPrivatesSize(pScreen, PRIVATE_PIXMAP); |
| 92 | pScreen->totalPixmapSize = |
| 93 | BitmapBytePad(pixmap_size * 8); |
| 94 | |
| 95 | /* let it be created on first use */ |
| 96 | pScreen->pScratchPixmap = NULL; |
| 97 | return TRUE; |
| 98 | } |
| 99 | |
| 100 | void |
| 101 | FreeScratchPixmapsForScreen(ScreenPtr pScreen) |
| 102 | { |
| 103 | FreeScratchPixmapHeader(pScreen->pScratchPixmap); |
| 104 | } |
| 105 | |
| 106 | /* callable by ddx */ |
| 107 | PixmapPtr |
| 108 | AllocatePixmap(ScreenPtr pScreen, int pixDataSize) |
| 109 | { |
| 110 | PixmapPtr pPixmap; |
| 111 | |
| 112 | assert(pScreen->totalPixmapSize > 0); |
| 113 | |
| 114 | if (pScreen->totalPixmapSize > ((size_t) - 1) - pixDataSize) |
| 115 | return NullPixmap; |
| 116 | |
| 117 | pPixmap = malloc(pScreen->totalPixmapSize + pixDataSize); |
| 118 | if (!pPixmap) |
| 119 | return NullPixmap; |
| 120 | |
| 121 | dixInitScreenPrivates(pScreen, pPixmap, pPixmap + 1, PRIVATE_PIXMAP); |
| 122 | return pPixmap; |
| 123 | } |
| 124 | |
| 125 | /* callable by ddx */ |
| 126 | void |
| 127 | FreePixmap(PixmapPtr pPixmap) |
| 128 | { |
| 129 | dixFiniPrivates(pPixmap, PRIVATE_PIXMAP); |
| 130 | free(pPixmap); |
| 131 | } |
| 132 | |
| 133 | PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave) |
| 134 | { |
| 135 | PixmapPtr spix; |
| 136 | int ret; |
| 137 | void *handle; |
| 138 | ScreenPtr master = pixmap->drawable.pScreen; |
| 139 | int depth = pixmap->drawable.depth; |
| 140 | |
| 141 | ret = master->SharePixmapBacking(pixmap, slave, &handle); |
| 142 | if (ret == FALSE) |
| 143 | return NULL; |
| 144 | |
| 145 | spix = slave->CreatePixmap(slave, 0, 0, depth, |
| 146 | CREATE_PIXMAP_USAGE_SHARED); |
| 147 | slave->ModifyPixmapHeader(spix, pixmap->drawable.width, |
| 148 | pixmap->drawable.height, depth, 0, |
| 149 | pixmap->devKind, NULL); |
| 150 | |
| 151 | /* have the slave pixmap take a reference on the master pixmap |
| 152 | later we destroy them both at the same time */ |
| 153 | pixmap->refcnt++; |
| 154 | |
| 155 | spix->master_pixmap = pixmap; |
| 156 | |
| 157 | ret = slave->SetSharedPixmapBacking(spix, handle); |
| 158 | if (ret == FALSE) { |
| 159 | slave->DestroyPixmap(spix); |
| 160 | return NULL; |
| 161 | } |
| 162 | |
| 163 | return spix; |
| 164 | } |
| 165 | |
| 166 | Bool |
| 167 | PixmapStartDirtyTracking(PixmapPtr src, |
| 168 | PixmapPtr slave_dst, |
| 169 | int x, int y) |
| 170 | { |
| 171 | ScreenPtr screen = src->drawable.pScreen; |
| 172 | PixmapDirtyUpdatePtr dirty_update; |
| 173 | |
| 174 | dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec)); |
| 175 | if (!dirty_update) |
| 176 | return FALSE; |
| 177 | |
| 178 | dirty_update->src = src; |
| 179 | dirty_update->slave_dst = slave_dst; |
| 180 | dirty_update->x = x; |
| 181 | dirty_update->y = y; |
| 182 | |
| 183 | dirty_update->damage = DamageCreate(NULL, NULL, |
| 184 | DamageReportNone, |
| 185 | TRUE, src->drawable.pScreen, |
| 186 | src->drawable.pScreen); |
| 187 | if (!dirty_update->damage) { |
| 188 | free(dirty_update); |
| 189 | return FALSE; |
| 190 | } |
| 191 | |
| 192 | DamageRegister(&src->drawable, dirty_update->damage); |
| 193 | xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list); |
| 194 | return TRUE; |
| 195 | } |
| 196 | |
| 197 | Bool |
| 198 | PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst) |
| 199 | { |
| 200 | ScreenPtr screen = src->drawable.pScreen; |
| 201 | PixmapDirtyUpdatePtr ent, safe; |
| 202 | |
| 203 | xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) { |
| 204 | if (ent->src == src && ent->slave_dst == slave_dst) { |
| 205 | DamageDestroy(ent->damage); |
| 206 | xorg_list_del(&ent->ent); |
| 207 | free(ent); |
| 208 | } |
| 209 | } |
| 210 | return TRUE; |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | * this function can possibly be improved and optimised, by clipping |
| 215 | * instead of iterating |
| 216 | */ |
| 217 | Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region) |
| 218 | { |
| 219 | ScreenPtr pScreen = dirty->src->drawable.pScreen; |
| 220 | int n; |
| 221 | BoxPtr b; |
| 222 | RegionPtr region = DamageRegion(dirty->damage); |
| 223 | GCPtr pGC; |
| 224 | PixmapPtr dst; |
| 225 | SourceValidateProcPtr SourceValidate; |
| 226 | |
| 227 | /* |
| 228 | * SourceValidate is used by the software cursor code |
| 229 | * to pull the cursor off of the screen when reading |
| 230 | * bits from the frame buffer. Bypassing this function |
| 231 | * leaves the software cursor in place |
| 232 | */ |
| 233 | SourceValidate = pScreen->SourceValidate; |
| 234 | pScreen->SourceValidate = NULL; |
| 235 | |
| 236 | RegionTranslate(dirty_region, dirty->x, dirty->y); |
| 237 | RegionIntersect(dirty_region, dirty_region, region); |
| 238 | |
| 239 | if (RegionNil(dirty_region)) { |
| 240 | RegionUninit(dirty_region); |
| 241 | return FALSE; |
| 242 | } |
| 243 | |
| 244 | dst = dirty->slave_dst->master_pixmap; |
| 245 | if (!dst) |
| 246 | dst = dirty->slave_dst; |
| 247 | |
| 248 | RegionTranslate(dirty_region, -dirty->x, -dirty->y); |
| 249 | n = RegionNumRects(dirty_region); |
| 250 | b = RegionRects(dirty_region); |
| 251 | |
| 252 | pGC = GetScratchGC(dirty->src->drawable.depth, pScreen); |
| 253 | ValidateGC(&dst->drawable, pGC); |
| 254 | |
| 255 | while (n--) { |
| 256 | BoxRec dst_box; |
| 257 | int w, h; |
| 258 | |
| 259 | dst_box = *b; |
| 260 | w = dst_box.x2 - dst_box.x1; |
| 261 | h = dst_box.y2 - dst_box.y1; |
| 262 | |
| 263 | pGC->ops->CopyArea(&dirty->src->drawable, &dst->drawable, pGC, |
| 264 | dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, dst_box.x1, dst_box.y1); |
| 265 | b++; |
| 266 | } |
| 267 | FreeScratchGC(pGC); |
| 268 | |
| 269 | pScreen->SourceValidate = SourceValidate; |
| 270 | return TRUE; |
| 271 | } |