| 1 | /* |
| 2 | * |
| 3 | * Copyright © 2000 SuSE, Inc. |
| 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, and that the name of SuSE not be used in advertising or |
| 10 | * publicity pertaining to distribution of the software without specific, |
| 11 | * written prior permission. SuSE makes no representations about the |
| 12 | * suitability of this software for any purpose. It is provided "as is" |
| 13 | * without express or implied warranty. |
| 14 | * |
| 15 | * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL |
| 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE |
| 17 | * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 18 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 19 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 20 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 21 | * |
| 22 | * Author: Keith Packard, SuSE, Inc. |
| 23 | */ |
| 24 | |
| 25 | #ifdef HAVE_DIX_CONFIG_H |
| 26 | #include <dix-config.h> |
| 27 | #endif |
| 28 | |
| 29 | #include <stdlib.h> |
| 30 | |
| 31 | #include "fb.h" |
| 32 | #include "fboverlay.h" |
| 33 | #include "shmint.h" |
| 34 | |
| 35 | static DevPrivateKeyRec fbOverlayScreenPrivateKeyRec; |
| 36 | |
| 37 | #define fbOverlayScreenPrivateKey (&fbOverlayScreenPrivateKeyRec) |
| 38 | |
| 39 | DevPrivateKey |
| 40 | fbOverlayGetScreenPrivateKey(void) |
| 41 | { |
| 42 | return fbOverlayScreenPrivateKey; |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | * Replace this if you want something supporting |
| 47 | * multiple overlays with the same depth |
| 48 | */ |
| 49 | Bool |
| 50 | fbOverlayCreateWindow(WindowPtr pWin) |
| 51 | { |
| 52 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); |
| 53 | int i; |
| 54 | PixmapPtr pPixmap; |
| 55 | |
| 56 | if (pWin->drawable.class != InputOutput) |
| 57 | return TRUE; |
| 58 | |
| 59 | if (pWin->drawable.bitsPerPixel == 32) |
| 60 | pWin->drawable.bitsPerPixel = |
| 61 | fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp; |
| 62 | |
| 63 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 64 | pPixmap = pScrPriv->layer[i].u.run.pixmap; |
| 65 | if (pWin->drawable.depth == pPixmap->drawable.depth) { |
| 66 | dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin), pPixmap); |
| 67 | /* |
| 68 | * Make sure layer keys are written correctly by |
| 69 | * having non-root layers set to full while the |
| 70 | * root layer is set to empty. This will cause |
| 71 | * all of the layers to get painted when the root |
| 72 | * is mapped |
| 73 | */ |
| 74 | if (!pWin->parent) { |
| 75 | RegionEmpty(&pScrPriv->layer[i].u.run.region); |
| 76 | } |
| 77 | return TRUE; |
| 78 | } |
| 79 | } |
| 80 | return FALSE; |
| 81 | } |
| 82 | |
| 83 | Bool |
| 84 | fbOverlayCloseScreen(ScreenPtr pScreen) |
| 85 | { |
| 86 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); |
| 87 | int i; |
| 88 | |
| 89 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 90 | (*pScreen->DestroyPixmap) (pScrPriv->layer[i].u.run.pixmap); |
| 91 | RegionUninit(&pScrPriv->layer[i].u.run.region); |
| 92 | } |
| 93 | return TRUE; |
| 94 | } |
| 95 | |
| 96 | /* |
| 97 | * Return layer containing this window |
| 98 | */ |
| 99 | int |
| 100 | fbOverlayWindowLayer(WindowPtr pWin) |
| 101 | { |
| 102 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); |
| 103 | int i; |
| 104 | |
| 105 | for (i = 0; i < pScrPriv->nlayers; i++) |
| 106 | if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin)) == |
| 107 | (pointer) pScrPriv->layer[i].u.run.pixmap) |
| 108 | return i; |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | Bool |
| 113 | fbOverlayCreateScreenResources(ScreenPtr pScreen) |
| 114 | { |
| 115 | int i; |
| 116 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); |
| 117 | PixmapPtr pPixmap; |
| 118 | pointer pbits; |
| 119 | int width; |
| 120 | int depth; |
| 121 | BoxRec box; |
| 122 | |
| 123 | if (!miCreateScreenResources(pScreen)) |
| 124 | return FALSE; |
| 125 | |
| 126 | box.x1 = 0; |
| 127 | box.y1 = 0; |
| 128 | box.x2 = pScreen->width; |
| 129 | box.y2 = pScreen->height; |
| 130 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 131 | pbits = pScrPriv->layer[i].u.init.pbits; |
| 132 | width = pScrPriv->layer[i].u.init.width; |
| 133 | depth = pScrPriv->layer[i].u.init.depth; |
| 134 | pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); |
| 135 | if (!pPixmap) |
| 136 | return FALSE; |
| 137 | if (!(*pScreen->ModifyPixmapHeader) (pPixmap, pScreen->width, |
| 138 | pScreen->height, depth, |
| 139 | BitsPerPixel(depth), |
| 140 | PixmapBytePad(width, depth), |
| 141 | pbits)) |
| 142 | return FALSE; |
| 143 | pScrPriv->layer[i].u.run.pixmap = pPixmap; |
| 144 | RegionInit(&pScrPriv->layer[i].u.run.region, &box, 0); |
| 145 | } |
| 146 | pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap; |
| 147 | return TRUE; |
| 148 | } |
| 149 | |
| 150 | void |
| 151 | fbOverlayPaintKey(DrawablePtr pDrawable, |
| 152 | RegionPtr pRegion, CARD32 pixel, int layer) |
| 153 | { |
| 154 | fbFillRegionSolid(pDrawable, pRegion, 0, |
| 155 | fbReplicatePixel(pixel, pDrawable->bitsPerPixel)); |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Track visible region for each layer |
| 160 | */ |
| 161 | void |
| 162 | fbOverlayUpdateLayerRegion(ScreenPtr pScreen, int layer, RegionPtr prgn) |
| 163 | { |
| 164 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); |
| 165 | int i; |
| 166 | RegionRec rgnNew; |
| 167 | |
| 168 | if (!prgn || !RegionNotEmpty(prgn)) |
| 169 | return; |
| 170 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 171 | if (i == layer) { |
| 172 | /* add new piece to this fb */ |
| 173 | RegionUnion(&pScrPriv->layer[i].u.run.region, |
| 174 | &pScrPriv->layer[i].u.run.region, prgn); |
| 175 | } |
| 176 | else if (RegionNotEmpty(&pScrPriv->layer[i].u.run.region)) { |
| 177 | /* paint new piece with chroma key */ |
| 178 | RegionNull(&rgnNew); |
| 179 | RegionIntersect(&rgnNew, prgn, &pScrPriv->layer[i].u.run.region); |
| 180 | (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable, |
| 181 | &rgnNew, pScrPriv->layer[i].key, i); |
| 182 | RegionUninit(&rgnNew); |
| 183 | /* remove piece from other fbs */ |
| 184 | RegionSubtract(&pScrPriv->layer[i].u.run.region, |
| 185 | &pScrPriv->layer[i].u.run.region, prgn); |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | /* |
| 191 | * Copy only areas in each layer containing real bits |
| 192 | */ |
| 193 | void |
| 194 | fbOverlayCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) |
| 195 | { |
| 196 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 197 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); |
| 198 | RegionRec rgnDst; |
| 199 | int dx, dy; |
| 200 | int i; |
| 201 | RegionRec layerRgn[FB_OVERLAY_MAX]; |
| 202 | PixmapPtr pPixmap; |
| 203 | |
| 204 | dx = ptOldOrg.x - pWin->drawable.x; |
| 205 | dy = ptOldOrg.y - pWin->drawable.y; |
| 206 | |
| 207 | /* |
| 208 | * Clip to existing bits |
| 209 | */ |
| 210 | RegionTranslate(prgnSrc, -dx, -dy); |
| 211 | RegionNull(&rgnDst); |
| 212 | RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); |
| 213 | RegionTranslate(&rgnDst, dx, dy); |
| 214 | /* |
| 215 | * Compute the portion of each fb affected by this copy |
| 216 | */ |
| 217 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 218 | RegionNull(&layerRgn[i]); |
| 219 | RegionIntersect(&layerRgn[i], &rgnDst, |
| 220 | &pScrPriv->layer[i].u.run.region); |
| 221 | if (RegionNotEmpty(&layerRgn[i])) { |
| 222 | RegionTranslate(&layerRgn[i], -dx, -dy); |
| 223 | pPixmap = pScrPriv->layer[i].u.run.pixmap; |
| 224 | miCopyRegion(&pPixmap->drawable, &pPixmap->drawable, |
| 225 | 0, |
| 226 | &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0, |
| 227 | (void *) (long) i); |
| 228 | } |
| 229 | } |
| 230 | /* |
| 231 | * Update regions |
| 232 | */ |
| 233 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 234 | if (RegionNotEmpty(&layerRgn[i])) |
| 235 | fbOverlayUpdateLayerRegion(pScreen, i, &layerRgn[i]); |
| 236 | |
| 237 | RegionUninit(&layerRgn[i]); |
| 238 | } |
| 239 | RegionUninit(&rgnDst); |
| 240 | } |
| 241 | |
| 242 | void |
| 243 | fbOverlayWindowExposures(WindowPtr pWin, |
| 244 | RegionPtr prgn, RegionPtr other_exposed) |
| 245 | { |
| 246 | fbOverlayUpdateLayerRegion(pWin->drawable.pScreen, |
| 247 | fbOverlayWindowLayer(pWin), prgn); |
| 248 | miWindowExposures(pWin, prgn, other_exposed); |
| 249 | } |
| 250 | |
| 251 | Bool |
| 252 | fbOverlaySetupScreen(ScreenPtr pScreen, |
| 253 | pointer pbits1, |
| 254 | pointer pbits2, |
| 255 | int xsize, |
| 256 | int ysize, |
| 257 | int dpix, |
| 258 | int dpiy, int width1, int width2, int bpp1, int bpp2) |
| 259 | { |
| 260 | return fbSetupScreen(pScreen, |
| 261 | pbits1, xsize, ysize, dpix, dpiy, width1, bpp1); |
| 262 | } |
| 263 | |
| 264 | static Bool |
| 265 | fb24_32OverlayCreateScreenResources(ScreenPtr pScreen) |
| 266 | { |
| 267 | FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); |
| 268 | int pitch; |
| 269 | Bool retval; |
| 270 | int i; |
| 271 | |
| 272 | if ((retval = fbOverlayCreateScreenResources(pScreen))) { |
| 273 | for (i = 0; i < pScrPriv->nlayers; i++) { |
| 274 | /* fix the screen pixmap */ |
| 275 | PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap; |
| 276 | |
| 277 | if (pPix->drawable.bitsPerPixel == 32) { |
| 278 | pPix->drawable.bitsPerPixel = 24; |
| 279 | pitch = BitmapBytePad(pPix->drawable.width * 24); |
| 280 | pPix->devKind = pitch; |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | return retval; |
| 286 | } |
| 287 | |
| 288 | Bool |
| 289 | fbOverlayFinishScreenInit(ScreenPtr pScreen, |
| 290 | pointer pbits1, |
| 291 | pointer pbits2, |
| 292 | int xsize, |
| 293 | int ysize, |
| 294 | int dpix, |
| 295 | int dpiy, |
| 296 | int width1, |
| 297 | int width2, |
| 298 | int bpp1, int bpp2, int depth1, int depth2) |
| 299 | { |
| 300 | VisualPtr visuals; |
| 301 | DepthPtr depths; |
| 302 | int nvisuals; |
| 303 | int ndepths; |
| 304 | int bpp = 0, imagebpp = 32; |
| 305 | VisualID defaultVisual; |
| 306 | FbOverlayScrPrivPtr pScrPriv; |
| 307 | |
| 308 | if (!dixRegisterPrivateKey |
| 309 | (&fbOverlayScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) |
| 310 | return FALSE; |
| 311 | |
| 312 | pScrPriv = malloc(sizeof(FbOverlayScrPrivRec)); |
| 313 | if (!pScrPriv) |
| 314 | return FALSE; |
| 315 | |
| 316 | if (bpp1 == 32 || bpp2 == 32) |
| 317 | bpp = 32; |
| 318 | else if (bpp1 == 24 || bpp2 == 24) |
| 319 | bpp = 24; |
| 320 | |
| 321 | if (bpp == 24) { |
| 322 | int f; |
| 323 | |
| 324 | imagebpp = 32; |
| 325 | /* |
| 326 | * Check to see if we're advertising a 24bpp image format, |
| 327 | * in which case windows will use it in preference to a 32 bit |
| 328 | * format. |
| 329 | */ |
| 330 | for (f = 0; f < screenInfo.numPixmapFormats; f++) { |
| 331 | if (screenInfo.formats[f].bitsPerPixel == 24) { |
| 332 | imagebpp = 24; |
| 333 | break; |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | if (imagebpp == 32) { |
| 338 | fbGetScreenPrivate(pScreen)->win32bpp = bpp; |
| 339 | fbGetScreenPrivate(pScreen)->pix32bpp = bpp; |
| 340 | } |
| 341 | else { |
| 342 | fbGetScreenPrivate(pScreen)->win32bpp = 32; |
| 343 | fbGetScreenPrivate(pScreen)->pix32bpp = 32; |
| 344 | } |
| 345 | |
| 346 | if (!fbInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &depth1, |
| 347 | &defaultVisual, ((unsigned long) 1 << (bpp1 - 1)) | |
| 348 | ((unsigned long) 1 << (bpp2 - 1)), 8)) { |
| 349 | free(pScrPriv); |
| 350 | return FALSE; |
| 351 | } |
| 352 | if (!miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0, |
| 353 | depth1, ndepths, depths, |
| 354 | defaultVisual, nvisuals, visuals)) { |
| 355 | free(pScrPriv); |
| 356 | return FALSE; |
| 357 | } |
| 358 | /* MI thinks there's no frame buffer */ |
| 359 | #ifdef MITSHM |
| 360 | ShmRegisterFbFuncs(pScreen); |
| 361 | #endif |
| 362 | pScreen->minInstalledCmaps = 1; |
| 363 | pScreen->maxInstalledCmaps = 2; |
| 364 | |
| 365 | pScrPriv->nlayers = 2; |
| 366 | pScrPriv->PaintKey = fbOverlayPaintKey; |
| 367 | pScrPriv->CopyWindow = fbCopyWindowProc; |
| 368 | pScrPriv->layer[0].u.init.pbits = pbits1; |
| 369 | pScrPriv->layer[0].u.init.width = width1; |
| 370 | pScrPriv->layer[0].u.init.depth = depth1; |
| 371 | |
| 372 | pScrPriv->layer[1].u.init.pbits = pbits2; |
| 373 | pScrPriv->layer[1].u.init.width = width2; |
| 374 | pScrPriv->layer[1].u.init.depth = depth2; |
| 375 | dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv); |
| 376 | |
| 377 | /* overwrite miCloseScreen with our own */ |
| 378 | pScreen->CloseScreen = fbOverlayCloseScreen; |
| 379 | pScreen->CreateScreenResources = fbOverlayCreateScreenResources; |
| 380 | pScreen->CreateWindow = fbOverlayCreateWindow; |
| 381 | pScreen->WindowExposures = fbOverlayWindowExposures; |
| 382 | pScreen->CopyWindow = fbOverlayCopyWindow; |
| 383 | if (bpp == 24 && imagebpp == 32) { |
| 384 | pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; |
| 385 | pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources; |
| 386 | } |
| 387 | |
| 388 | return TRUE; |
| 389 | } |