diff options
Diffstat (limited to 'xorg-server/fb/fboverlay.c')
-rw-r--r-- | xorg-server/fb/fboverlay.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/xorg-server/fb/fboverlay.c b/xorg-server/fb/fboverlay.c new file mode 100644 index 000000000..f9f7c52a3 --- /dev/null +++ b/xorg-server/fb/fboverlay.c @@ -0,0 +1,436 @@ +/* + * + * 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 DevPrivateKey fbOverlayScreenPrivateKey = &fbOverlayScreenPrivateKey; + +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; + fbCopyRegion (&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; +} |