/* * * Copyright © 2000 SuSE, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Keith Packard, SuSE, Inc. */ #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif #include <stdlib.h> #include "fb.h" #include "fboverlay.h" #include "shmint.h" static int fbOverlayScreenPrivateKeyIndex; static DevPrivateKey fbOverlayScreenPrivateKey = &fbOverlayScreenPrivateKeyIndex; DevPrivateKey fbOverlayGetScreenPrivateKey(void) { return fbOverlayScreenPrivateKey; } /* * Replace this if you want something supporting * multiple overlays with the same depth */ Bool fbOverlayCreateWindow(WindowPtr pWin) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); int i; PixmapPtr pPixmap; if (pWin->drawable.class != InputOutput) return TRUE; #ifdef FB_SCREEN_PRIVATE if (pWin->drawable.bitsPerPixel == 32) pWin->drawable.bitsPerPixel = fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp; #endif for (i = 0; i < pScrPriv->nlayers; i++) { pPixmap = pScrPriv->layer[i].u.run.pixmap; if (pWin->drawable.depth == pPixmap->drawable.depth) { dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(), pPixmap); /* * Make sure layer keys are written correctly by * having non-root layers set to full while the * root layer is set to empty. This will cause * all of the layers to get painted when the root * is mapped */ if (!pWin->parent) { REGION_EMPTY (pWin->drawable.pScreen, &pScrPriv->layer[i].u.run.region); } return TRUE; } } return FALSE; } Bool fbOverlayCloseScreen (int iScreen, ScreenPtr pScreen) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); int i; for (i = 0; i < pScrPriv->nlayers; i++) { (*pScreen->DestroyPixmap)(pScrPriv->layer[i].u.run.pixmap); REGION_UNINIT (pScreen, &pScrPriv->layer[i].u.run.region); } return TRUE; } /* * Return layer containing this window */ int fbOverlayWindowLayer(WindowPtr pWin) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); int i; for (i = 0; i < pScrPriv->nlayers; i++) if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey()) == (pointer) pScrPriv->layer[i].u.run.pixmap) return i; return 0; } Bool fbOverlayCreateScreenResources(ScreenPtr pScreen) { int i; FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); PixmapPtr pPixmap; pointer pbits; int width; int depth; BoxRec box; if (!miCreateScreenResources(pScreen)) return FALSE; box.x1 = 0; box.y1 = 0; box.x2 = pScreen->width; box.y2 = pScreen->height; for (i = 0; i < pScrPriv->nlayers; i++) { pbits = pScrPriv->layer[i].u.init.pbits; width = pScrPriv->layer[i].u.init.width; depth = pScrPriv->layer[i].u.init.depth; pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); if (!pPixmap) return FALSE; if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, pScreen->height, depth, BitsPerPixel(depth), PixmapBytePad(width, depth), pbits)) return FALSE; pScrPriv->layer[i].u.run.pixmap = pPixmap; REGION_INIT(pScreen, &pScrPriv->layer[i].u.run.region, &box, 0); } pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap; return TRUE; } void fbOverlayPaintKey (DrawablePtr pDrawable, RegionPtr pRegion, CARD32 pixel, int layer) { fbFillRegionSolid (pDrawable, pRegion, 0, fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); } /* * Track visible region for each layer */ void fbOverlayUpdateLayerRegion (ScreenPtr pScreen, int layer, RegionPtr prgn) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); int i; RegionRec rgnNew; if (!prgn || !REGION_NOTEMPTY(pScreen, prgn)) return; for (i = 0; i < pScrPriv->nlayers; i++) { if (i == layer) { /* add new piece to this fb */ REGION_UNION (pScreen, &pScrPriv->layer[i].u.run.region, &pScrPriv->layer[i].u.run.region, prgn); } else if (REGION_NOTEMPTY (pScreen, &pScrPriv->layer[i].u.run.region)) { /* paint new piece with chroma key */ REGION_NULL (pScreen, &rgnNew); REGION_INTERSECT (pScreen, &rgnNew, prgn, &pScrPriv->layer[i].u.run.region); (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable, &rgnNew, pScrPriv->layer[i].key, i); REGION_UNINIT(pScreen, &rgnNew); /* remove piece from other fbs */ REGION_SUBTRACT (pScreen, &pScrPriv->layer[i].u.run.region, &pScrPriv->layer[i].u.run.region, prgn); } } } /* * Copy only areas in each layer containing real bits */ void fbOverlayCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) { ScreenPtr pScreen = pWin->drawable.pScreen; FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen); RegionRec rgnDst; int dx, dy; int i; RegionRec layerRgn[FB_OVERLAY_MAX]; PixmapPtr pPixmap; dx = ptOldOrg.x - pWin->drawable.x; dy = ptOldOrg.y - pWin->drawable.y; /* * Clip to existing bits */ REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); REGION_NULL (pScreen, &rgnDst); REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); REGION_TRANSLATE(pScreen, &rgnDst, dx, dy); /* * Compute the portion of each fb affected by this copy */ for (i = 0; i < pScrPriv->nlayers; i++) { REGION_NULL (pScreen, &layerRgn[i]); REGION_INTERSECT(pScreen, &layerRgn[i], &rgnDst, &pScrPriv->layer[i].u.run.region); if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) { REGION_TRANSLATE(pScreen, &layerRgn[i], -dx, -dy); pPixmap = pScrPriv->layer[i].u.run.pixmap; miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 0, &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0, (void *)(long) i); } } /* * Update regions */ for (i = 0; i < pScrPriv->nlayers; i++) { if (REGION_NOTEMPTY (pScreen, &layerRgn[i])) fbOverlayUpdateLayerRegion (pScreen, i, &layerRgn[i]); REGION_UNINIT(pScreen, &layerRgn[i]); } REGION_UNINIT(pScreen, &rgnDst); } void fbOverlayWindowExposures (WindowPtr pWin, RegionPtr prgn, RegionPtr other_exposed) { fbOverlayUpdateLayerRegion (pWin->drawable.pScreen, fbOverlayWindowLayer (pWin), prgn); miWindowExposures(pWin, prgn, other_exposed); } Bool fbOverlaySetupScreen(ScreenPtr pScreen, pointer pbits1, pointer pbits2, int xsize, int ysize, int dpix, int dpiy, int width1, int width2, int bpp1, int bpp2) { return fbSetupScreen (pScreen, pbits1, xsize, ysize, dpix, dpiy, width1, bpp1); } static Bool fb24_32OverlayCreateScreenResources(ScreenPtr pScreen) { FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen); int pitch; Bool retval; int i; if((retval = fbOverlayCreateScreenResources(pScreen))) { for (i = 0; i < pScrPriv->nlayers; i++) { /* fix the screen pixmap */ PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap; if (pPix->drawable.bitsPerPixel == 32) { pPix->drawable.bitsPerPixel = 24; pitch = BitmapBytePad(pPix->drawable.width * 24); pPix->devKind = pitch; } } } return retval; } Bool fbOverlayFinishScreenInit(ScreenPtr pScreen, pointer pbits1, pointer pbits2, int xsize, int ysize, int dpix, int dpiy, int width1, int width2, int bpp1, int bpp2, int depth1, int depth2) { VisualPtr visuals; DepthPtr depths; int nvisuals; int ndepths; int bpp = 0, imagebpp = 32; VisualID defaultVisual; FbOverlayScrPrivPtr pScrPriv; pScrPriv = xalloc (sizeof (FbOverlayScrPrivRec)); if (!pScrPriv) return FALSE; #ifdef FB_24_32BIT if (bpp1 == 32 || bpp2 == 32) bpp = 32; else if (bpp1 == 24 || bpp2 == 24) bpp = 24; if (bpp == 24) { int f; imagebpp = 32; /* * Check to see if we're advertising a 24bpp image format, * in which case windows will use it in preference to a 32 bit * format. */ for (f = 0; f < screenInfo.numPixmapFormats; f++) { if (screenInfo.formats[f].bitsPerPixel == 24) { imagebpp = 24; break; } } } #endif #ifdef FB_SCREEN_PRIVATE if (imagebpp == 32) { fbGetScreenPrivate(pScreen)->win32bpp = bpp; fbGetScreenPrivate(pScreen)->pix32bpp = bpp; } else { fbGetScreenPrivate(pScreen)->win32bpp = 32; fbGetScreenPrivate(pScreen)->pix32bpp = 32; } #endif if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &depth1, &defaultVisual, ((unsigned long)1<<(bpp1-1)) | ((unsigned long)1<<(bpp2-1)), 8)) return FALSE; if (! miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0, depth1, ndepths, depths, defaultVisual, nvisuals, visuals)) return FALSE; /* MI thinks there's no frame buffer */ #ifdef MITSHM ShmRegisterFbFuncs(pScreen); #endif pScreen->minInstalledCmaps = 1; pScreen->maxInstalledCmaps = 2; pScrPriv->nlayers = 2; pScrPriv->PaintKey = fbOverlayPaintKey; pScrPriv->CopyWindow = fbCopyWindowProc; pScrPriv->layer[0].u.init.pbits = pbits1; pScrPriv->layer[0].u.init.width = width1; pScrPriv->layer[0].u.init.depth = depth1; pScrPriv->layer[1].u.init.pbits = pbits2; pScrPriv->layer[1].u.init.width = width2; pScrPriv->layer[1].u.init.depth = depth2; dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv); /* overwrite miCloseScreen with our own */ pScreen->CloseScreen = fbOverlayCloseScreen; pScreen->CreateScreenResources = fbOverlayCreateScreenResources; pScreen->CreateWindow = fbOverlayCreateWindow; pScreen->WindowExposures = fbOverlayWindowExposures; pScreen->CopyWindow = fbOverlayCopyWindow; #ifdef FB_24_32BIT if (bpp == 24 && imagebpp == 32) { pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader; pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources; } #endif return TRUE; }