1706f2543Smrg/*
2706f2543Smrg *
3706f2543Smrg * Copyright © 2000 SuSE, Inc.
4706f2543Smrg *
5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
7706f2543Smrg * the above copyright notice appear in all copies and that both that
8706f2543Smrg * copyright notice and this permission notice appear in supporting
9706f2543Smrg * documentation, and that the name of SuSE not be used in advertising or
10706f2543Smrg * publicity pertaining to distribution of the software without specific,
11706f2543Smrg * written prior permission.  SuSE makes no representations about the
12706f2543Smrg * suitability of this software for any purpose.  It is provided "as is"
13706f2543Smrg * without express or implied warranty.
14706f2543Smrg *
15706f2543Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16706f2543Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17706f2543Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18706f2543Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19706f2543Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg *
22706f2543Smrg * Author:  Keith Packard, SuSE, Inc.
23706f2543Smrg */
24706f2543Smrg
25706f2543Smrg
26706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
27706f2543Smrg#include <dix-config.h>
28706f2543Smrg#endif
29706f2543Smrg
30706f2543Smrg#include <stdlib.h>
31706f2543Smrg
32706f2543Smrg#include "fb.h"
33706f2543Smrg#include "fboverlay.h"
34706f2543Smrg#include "shmint.h"
35706f2543Smrg
36706f2543Smrgstatic DevPrivateKeyRec fbOverlayScreenPrivateKeyRec;
37706f2543Smrg#define fbOverlayScreenPrivateKey (&fbOverlayScreenPrivateKeyRec)
38706f2543Smrg
39706f2543SmrgDevPrivateKey fbOverlayGetScreenPrivateKey(void)
40706f2543Smrg{
41706f2543Smrg    return fbOverlayScreenPrivateKey;
42706f2543Smrg}
43706f2543Smrg
44706f2543Smrg/*
45706f2543Smrg * Replace this if you want something supporting
46706f2543Smrg * multiple overlays with the same depth
47706f2543Smrg */
48706f2543SmrgBool
49706f2543SmrgfbOverlayCreateWindow(WindowPtr pWin)
50706f2543Smrg{
51706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen);
52706f2543Smrg    int			i;
53706f2543Smrg    PixmapPtr		pPixmap;
54706f2543Smrg
55706f2543Smrg    if (pWin->drawable.class != InputOutput)
56706f2543Smrg	return TRUE;
57706f2543Smrg
58706f2543Smrg#ifdef FB_SCREEN_PRIVATE
59706f2543Smrg    if (pWin->drawable.bitsPerPixel == 32)
60706f2543Smrg	pWin->drawable.bitsPerPixel = fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp;
61706f2543Smrg#endif
62706f2543Smrg
63706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
64706f2543Smrg    {
65706f2543Smrg	pPixmap = pScrPriv->layer[i].u.run.pixmap;
66706f2543Smrg	if (pWin->drawable.depth == pPixmap->drawable.depth)
67706f2543Smrg	{
68706f2543Smrg	    dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(), pPixmap);
69706f2543Smrg	    /*
70706f2543Smrg	     * Make sure layer keys are written correctly by
71706f2543Smrg	     * having non-root layers set to full while the
72706f2543Smrg	     * root layer is set to empty.  This will cause
73706f2543Smrg	     * all of the layers to get painted when the root
74706f2543Smrg	     * is mapped
75706f2543Smrg	     */
76706f2543Smrg	    if (!pWin->parent)
77706f2543Smrg	    {
78706f2543Smrg		RegionEmpty(&pScrPriv->layer[i].u.run.region);
79706f2543Smrg	    }
80706f2543Smrg	    return TRUE;
81706f2543Smrg	}
82706f2543Smrg    }
83706f2543Smrg    return FALSE;
84706f2543Smrg}
85706f2543Smrg
86706f2543SmrgBool
87706f2543SmrgfbOverlayCloseScreen (int iScreen, ScreenPtr pScreen)
88706f2543Smrg{
89706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv = fbOverlayGetScrPriv(pScreen);
90706f2543Smrg    int			i;
91706f2543Smrg
92706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
93706f2543Smrg    {
94706f2543Smrg	(*pScreen->DestroyPixmap)(pScrPriv->layer[i].u.run.pixmap);
95706f2543Smrg	RegionUninit(&pScrPriv->layer[i].u.run.region);
96706f2543Smrg    }
97706f2543Smrg    return TRUE;
98706f2543Smrg}
99706f2543Smrg
100706f2543Smrg/*
101706f2543Smrg * Return layer containing this window
102706f2543Smrg */
103706f2543Smrgint
104706f2543SmrgfbOverlayWindowLayer(WindowPtr pWin)
105706f2543Smrg{
106706f2543Smrg    FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen);
107706f2543Smrg    int                 i;
108706f2543Smrg
109706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
110706f2543Smrg	if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey()) ==
111706f2543Smrg	    (pointer) pScrPriv->layer[i].u.run.pixmap)
112706f2543Smrg	    return i;
113706f2543Smrg    return 0;
114706f2543Smrg}
115706f2543Smrg
116706f2543SmrgBool
117706f2543SmrgfbOverlayCreateScreenResources(ScreenPtr pScreen)
118706f2543Smrg{
119706f2543Smrg    int			i;
120706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv = fbOverlayGetScrPriv(pScreen);
121706f2543Smrg    PixmapPtr		pPixmap;
122706f2543Smrg    pointer		pbits;
123706f2543Smrg    int			width;
124706f2543Smrg    int			depth;
125706f2543Smrg    BoxRec		box;
126706f2543Smrg
127706f2543Smrg    if (!miCreateScreenResources(pScreen))
128706f2543Smrg	return FALSE;
129706f2543Smrg
130706f2543Smrg    box.x1 = 0;
131706f2543Smrg    box.y1 = 0;
132706f2543Smrg    box.x2 = pScreen->width;
133706f2543Smrg    box.y2 = pScreen->height;
134706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
135706f2543Smrg    {
136706f2543Smrg	pbits = pScrPriv->layer[i].u.init.pbits;
137706f2543Smrg	width = pScrPriv->layer[i].u.init.width;
138706f2543Smrg	depth = pScrPriv->layer[i].u.init.depth;
139706f2543Smrg	pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
140706f2543Smrg	if (!pPixmap)
141706f2543Smrg	    return FALSE;
142706f2543Smrg	if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width,
143706f2543Smrg					    pScreen->height, depth,
144706f2543Smrg					    BitsPerPixel(depth),
145706f2543Smrg					    PixmapBytePad(width, depth),
146706f2543Smrg					    pbits))
147706f2543Smrg	    return FALSE;
148706f2543Smrg	pScrPriv->layer[i].u.run.pixmap = pPixmap;
149706f2543Smrg	RegionInit(&pScrPriv->layer[i].u.run.region, &box, 0);
150706f2543Smrg    }
151706f2543Smrg    pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap;
152706f2543Smrg    return TRUE;
153706f2543Smrg}
154706f2543Smrg
155706f2543Smrgvoid
156706f2543SmrgfbOverlayPaintKey (DrawablePtr	pDrawable,
157706f2543Smrg		   RegionPtr	pRegion,
158706f2543Smrg		   CARD32	pixel,
159706f2543Smrg		   int		layer)
160706f2543Smrg{
161706f2543Smrg    fbFillRegionSolid (pDrawable, pRegion, 0,
162706f2543Smrg		       fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
163706f2543Smrg}
164706f2543Smrg
165706f2543Smrg/*
166706f2543Smrg * Track visible region for each layer
167706f2543Smrg */
168706f2543Smrgvoid
169706f2543SmrgfbOverlayUpdateLayerRegion (ScreenPtr	pScreen,
170706f2543Smrg			    int		layer,
171706f2543Smrg			    RegionPtr	prgn)
172706f2543Smrg{
173706f2543Smrg    FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
174706f2543Smrg    int			i;
175706f2543Smrg    RegionRec		rgnNew;
176706f2543Smrg
177706f2543Smrg    if (!prgn || !RegionNotEmpty(prgn))
178706f2543Smrg	return;
179706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
180706f2543Smrg    {
181706f2543Smrg	if (i == layer)
182706f2543Smrg	{
183706f2543Smrg	    /* add new piece to this fb */
184706f2543Smrg	    RegionUnion(&pScrPriv->layer[i].u.run.region,
185706f2543Smrg			&pScrPriv->layer[i].u.run.region,
186706f2543Smrg			prgn);
187706f2543Smrg	}
188706f2543Smrg	else if (RegionNotEmpty(&pScrPriv->layer[i].u.run.region))
189706f2543Smrg	{
190706f2543Smrg	    /* paint new piece with chroma key */
191706f2543Smrg	    RegionNull(&rgnNew);
192706f2543Smrg	    RegionIntersect(&rgnNew, prgn,
193706f2543Smrg			    &pScrPriv->layer[i].u.run.region);
194706f2543Smrg	    (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable,
195706f2543Smrg				   &rgnNew,
196706f2543Smrg				   pScrPriv->layer[i].key,
197706f2543Smrg				   i);
198706f2543Smrg	    RegionUninit(&rgnNew);
199706f2543Smrg	    /* remove piece from other fbs */
200706f2543Smrg	    RegionSubtract(&pScrPriv->layer[i].u.run.region,
201706f2543Smrg			   &pScrPriv->layer[i].u.run.region,
202706f2543Smrg			   prgn);
203706f2543Smrg	}
204706f2543Smrg    }
205706f2543Smrg}
206706f2543Smrg
207706f2543Smrg/*
208706f2543Smrg * Copy only areas in each layer containing real bits
209706f2543Smrg */
210706f2543Smrgvoid
211706f2543SmrgfbOverlayCopyWindow(WindowPtr	pWin,
212706f2543Smrg		    DDXPointRec	ptOldOrg,
213706f2543Smrg		    RegionPtr	prgnSrc)
214706f2543Smrg{
215706f2543Smrg    ScreenPtr		pScreen = pWin->drawable.pScreen;
216706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv = fbOverlayGetScrPriv(pScreen);
217706f2543Smrg    RegionRec		rgnDst;
218706f2543Smrg    int			dx, dy;
219706f2543Smrg    int			i;
220706f2543Smrg    RegionRec		layerRgn[FB_OVERLAY_MAX];
221706f2543Smrg    PixmapPtr		pPixmap;
222706f2543Smrg
223706f2543Smrg    dx = ptOldOrg.x - pWin->drawable.x;
224706f2543Smrg    dy = ptOldOrg.y - pWin->drawable.y;
225706f2543Smrg
226706f2543Smrg    /*
227706f2543Smrg     * Clip to existing bits
228706f2543Smrg     */
229706f2543Smrg    RegionTranslate(prgnSrc, -dx, -dy);
230706f2543Smrg    RegionNull(&rgnDst);
231706f2543Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
232706f2543Smrg    RegionTranslate(&rgnDst, dx, dy);
233706f2543Smrg    /*
234706f2543Smrg     * Compute the portion of each fb affected by this copy
235706f2543Smrg     */
236706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
237706f2543Smrg    {
238706f2543Smrg	RegionNull(&layerRgn[i]);
239706f2543Smrg	RegionIntersect(&layerRgn[i], &rgnDst,
240706f2543Smrg			 &pScrPriv->layer[i].u.run.region);
241706f2543Smrg	if (RegionNotEmpty(&layerRgn[i]))
242706f2543Smrg	{
243706f2543Smrg	    RegionTranslate(&layerRgn[i], -dx, -dy);
244706f2543Smrg	    pPixmap = pScrPriv->layer[i].u.run.pixmap;
245706f2543Smrg	    miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
246706f2543Smrg			  0,
247706f2543Smrg			  &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0,
248706f2543Smrg			  (void *)(long) i);
249706f2543Smrg	}
250706f2543Smrg    }
251706f2543Smrg    /*
252706f2543Smrg     * Update regions
253706f2543Smrg     */
254706f2543Smrg    for (i = 0; i < pScrPriv->nlayers; i++)
255706f2543Smrg    {
256706f2543Smrg	if (RegionNotEmpty(&layerRgn[i]))
257706f2543Smrg	    fbOverlayUpdateLayerRegion (pScreen, i, &layerRgn[i]);
258706f2543Smrg
259706f2543Smrg	RegionUninit(&layerRgn[i]);
260706f2543Smrg    }
261706f2543Smrg    RegionUninit(&rgnDst);
262706f2543Smrg}
263706f2543Smrg
264706f2543Smrgvoid
265706f2543SmrgfbOverlayWindowExposures (WindowPtr	pWin,
266706f2543Smrg			  RegionPtr	prgn,
267706f2543Smrg			  RegionPtr	other_exposed)
268706f2543Smrg{
269706f2543Smrg    fbOverlayUpdateLayerRegion (pWin->drawable.pScreen,
270706f2543Smrg				fbOverlayWindowLayer (pWin),
271706f2543Smrg				prgn);
272706f2543Smrg    miWindowExposures(pWin, prgn, other_exposed);
273706f2543Smrg}
274706f2543Smrg
275706f2543SmrgBool
276706f2543SmrgfbOverlaySetupScreen(ScreenPtr	pScreen,
277706f2543Smrg		     pointer	pbits1,
278706f2543Smrg		     pointer	pbits2,
279706f2543Smrg		     int	xsize,
280706f2543Smrg		     int	ysize,
281706f2543Smrg		     int	dpix,
282706f2543Smrg		     int	dpiy,
283706f2543Smrg		     int	width1,
284706f2543Smrg		     int	width2,
285706f2543Smrg		     int	bpp1,
286706f2543Smrg		     int	bpp2)
287706f2543Smrg{
288706f2543Smrg    return fbSetupScreen (pScreen,
289706f2543Smrg			  pbits1,
290706f2543Smrg			  xsize,
291706f2543Smrg			  ysize,
292706f2543Smrg			  dpix,
293706f2543Smrg			  dpiy,
294706f2543Smrg			  width1,
295706f2543Smrg			  bpp1);
296706f2543Smrg}
297706f2543Smrg
298706f2543Smrgstatic Bool
299706f2543Smrgfb24_32OverlayCreateScreenResources(ScreenPtr pScreen)
300706f2543Smrg{
301706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv = fbOverlayGetScrPriv(pScreen);
302706f2543Smrg    int pitch;
303706f2543Smrg    Bool retval;
304706f2543Smrg    int i;
305706f2543Smrg
306706f2543Smrg    if((retval = fbOverlayCreateScreenResources(pScreen))) {
307706f2543Smrg	for (i = 0; i < pScrPriv->nlayers; i++)
308706f2543Smrg	{
309706f2543Smrg	    /* fix the screen pixmap */
310706f2543Smrg	    PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap;
311706f2543Smrg	    if (pPix->drawable.bitsPerPixel == 32) {
312706f2543Smrg		pPix->drawable.bitsPerPixel = 24;
313706f2543Smrg		pitch = BitmapBytePad(pPix->drawable.width * 24);
314706f2543Smrg		pPix->devKind = pitch;
315706f2543Smrg	    }
316706f2543Smrg	}
317706f2543Smrg    }
318706f2543Smrg
319706f2543Smrg    return retval;
320706f2543Smrg}
321706f2543Smrg
322706f2543SmrgBool
323706f2543SmrgfbOverlayFinishScreenInit(ScreenPtr	pScreen,
324706f2543Smrg			  pointer	pbits1,
325706f2543Smrg			  pointer	pbits2,
326706f2543Smrg			  int		xsize,
327706f2543Smrg			  int		ysize,
328706f2543Smrg			  int		dpix,
329706f2543Smrg			  int		dpiy,
330706f2543Smrg			  int		width1,
331706f2543Smrg			  int		width2,
332706f2543Smrg			  int		bpp1,
333706f2543Smrg			  int		bpp2,
334706f2543Smrg			  int		depth1,
335706f2543Smrg			  int		depth2)
336706f2543Smrg{
337706f2543Smrg    VisualPtr	visuals;
338706f2543Smrg    DepthPtr	depths;
339706f2543Smrg    int		nvisuals;
340706f2543Smrg    int		ndepths;
341706f2543Smrg    int		bpp = 0, imagebpp = 32;
342706f2543Smrg    VisualID	defaultVisual;
343706f2543Smrg    FbOverlayScrPrivPtr	pScrPriv;
344706f2543Smrg
345706f2543Smrg    if (!dixRegisterPrivateKey(&fbOverlayScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
346706f2543Smrg	return FALSE;
347706f2543Smrg
348706f2543Smrg    pScrPriv = malloc(sizeof (FbOverlayScrPrivRec));
349706f2543Smrg    if (!pScrPriv)
350706f2543Smrg	return FALSE;
351706f2543Smrg
352706f2543Smrg#ifdef FB_24_32BIT
353706f2543Smrg    if (bpp1 == 32 || bpp2 == 32)
354706f2543Smrg	bpp = 32;
355706f2543Smrg    else if (bpp1 == 24 || bpp2 == 24)
356706f2543Smrg	bpp = 24;
357706f2543Smrg
358706f2543Smrg    if (bpp == 24)
359706f2543Smrg    {
360706f2543Smrg	int	f;
361706f2543Smrg
362706f2543Smrg	imagebpp = 32;
363706f2543Smrg	/*
364706f2543Smrg	 * Check to see if we're advertising a 24bpp image format,
365706f2543Smrg	 * in which case windows will use it in preference to a 32 bit
366706f2543Smrg	 * format.
367706f2543Smrg	 */
368706f2543Smrg	for (f = 0; f < screenInfo.numPixmapFormats; f++)
369706f2543Smrg	{
370706f2543Smrg	    if (screenInfo.formats[f].bitsPerPixel == 24)
371706f2543Smrg	    {
372706f2543Smrg		imagebpp = 24;
373706f2543Smrg		break;
374706f2543Smrg	    }
375706f2543Smrg	}
376706f2543Smrg    }
377706f2543Smrg#endif
378706f2543Smrg#ifdef FB_SCREEN_PRIVATE
379706f2543Smrg    if (imagebpp == 32)
380706f2543Smrg    {
381706f2543Smrg	fbGetScreenPrivate(pScreen)->win32bpp = bpp;
382706f2543Smrg	fbGetScreenPrivate(pScreen)->pix32bpp = bpp;
383706f2543Smrg    }
384706f2543Smrg    else
385706f2543Smrg    {
386706f2543Smrg	fbGetScreenPrivate(pScreen)->win32bpp = 32;
387706f2543Smrg	fbGetScreenPrivate(pScreen)->pix32bpp = 32;
388706f2543Smrg    }
389706f2543Smrg#endif
390706f2543Smrg
391706f2543Smrg    if (!fbInitVisuals (&visuals, &depths, &nvisuals, &ndepths, &depth1,
392706f2543Smrg			&defaultVisual, ((unsigned long)1<<(bpp1-1)) |
393706f2543Smrg			((unsigned long)1<<(bpp2-1)), 8)) {
394706f2543Smrg	free(pScrPriv);
395706f2543Smrg	return FALSE;
396706f2543Smrg    }
397706f2543Smrg    if (! miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0,
398706f2543Smrg			depth1, ndepths, depths,
399706f2543Smrg			defaultVisual, nvisuals, visuals)) {
400706f2543Smrg	free(pScrPriv);
401706f2543Smrg	return FALSE;
402706f2543Smrg    }
403706f2543Smrg    /* MI thinks there's no frame buffer */
404706f2543Smrg#ifdef MITSHM
405706f2543Smrg    ShmRegisterFbFuncs(pScreen);
406706f2543Smrg#endif
407706f2543Smrg    pScreen->minInstalledCmaps = 1;
408706f2543Smrg    pScreen->maxInstalledCmaps = 2;
409706f2543Smrg
410706f2543Smrg    pScrPriv->nlayers = 2;
411706f2543Smrg    pScrPriv->PaintKey = fbOverlayPaintKey;
412706f2543Smrg    pScrPriv->CopyWindow = fbCopyWindowProc;
413706f2543Smrg    pScrPriv->layer[0].u.init.pbits = pbits1;
414706f2543Smrg    pScrPriv->layer[0].u.init.width = width1;
415706f2543Smrg    pScrPriv->layer[0].u.init.depth = depth1;
416706f2543Smrg
417706f2543Smrg    pScrPriv->layer[1].u.init.pbits = pbits2;
418706f2543Smrg    pScrPriv->layer[1].u.init.width = width2;
419706f2543Smrg    pScrPriv->layer[1].u.init.depth = depth2;
420706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv);
421706f2543Smrg
422706f2543Smrg    /* overwrite miCloseScreen with our own */
423706f2543Smrg    pScreen->CloseScreen = fbOverlayCloseScreen;
424706f2543Smrg    pScreen->CreateScreenResources = fbOverlayCreateScreenResources;
425706f2543Smrg    pScreen->CreateWindow = fbOverlayCreateWindow;
426706f2543Smrg    pScreen->WindowExposures = fbOverlayWindowExposures;
427706f2543Smrg    pScreen->CopyWindow = fbOverlayCopyWindow;
428706f2543Smrg#ifdef FB_24_32BIT
429706f2543Smrg    if (bpp == 24 && imagebpp == 32)
430706f2543Smrg    {
431706f2543Smrg	pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader;
432706f2543Smrg  	pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources;
433706f2543Smrg    }
434706f2543Smrg#endif
435706f2543Smrg
436706f2543Smrg    return TRUE;
437706f2543Smrg}
438