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