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
fbOverlayGetScreenPrivateKey(void)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
fbOverlayCreateWindow(WindowPtr pWin)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     for (i = 0; i < pScrPriv->nlayers; i++) {
60         pPixmap = pScrPriv->layer[i].u.run.pixmap;
61         if (pWin->drawable.depth == pPixmap->drawable.depth) {
62             dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin), pPixmap);
63             /*
64              * Make sure layer keys are written correctly by
65              * having non-root layers set to full while the
66              * root layer is set to empty.  This will cause
67              * all of the layers to get painted when the root
68              * is mapped
69              */
70             if (!pWin->parent) {
71                 RegionEmpty(&pScrPriv->layer[i].u.run.region);
72             }
73             return TRUE;
74         }
75     }
76     return FALSE;
77 }
78 
79 Bool
fbOverlayCloseScreen(ScreenPtr pScreen)80 fbOverlayCloseScreen(ScreenPtr pScreen)
81 {
82     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
83     int i;
84 
85     for (i = 0; i < pScrPriv->nlayers; i++) {
86         (*pScreen->DestroyPixmap) (pScrPriv->layer[i].u.run.pixmap);
87         RegionUninit(&pScrPriv->layer[i].u.run.region);
88     }
89     return TRUE;
90 }
91 
92 /*
93  * Return layer containing this window
94  */
95 int
fbOverlayWindowLayer(WindowPtr pWin)96 fbOverlayWindowLayer(WindowPtr pWin)
97 {
98     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen);
99     int i;
100 
101     for (i = 0; i < pScrPriv->nlayers; i++)
102         if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin)) ==
103             (void *) pScrPriv->layer[i].u.run.pixmap)
104             return i;
105     return 0;
106 }
107 
108 Bool
fbOverlayCreateScreenResources(ScreenPtr pScreen)109 fbOverlayCreateScreenResources(ScreenPtr pScreen)
110 {
111     int i;
112     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
113     PixmapPtr pPixmap;
114     void *pbits;
115     int width;
116     int depth;
117     BoxRec box;
118 
119     if (!miCreateScreenResources(pScreen))
120         return FALSE;
121 
122     box.x1 = 0;
123     box.y1 = 0;
124     box.x2 = pScreen->width;
125     box.y2 = pScreen->height;
126     for (i = 0; i < pScrPriv->nlayers; i++) {
127         pbits = pScrPriv->layer[i].u.init.pbits;
128         width = pScrPriv->layer[i].u.init.width;
129         depth = pScrPriv->layer[i].u.init.depth;
130         pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
131         if (!pPixmap)
132             return FALSE;
133         if (!(*pScreen->ModifyPixmapHeader) (pPixmap, pScreen->width,
134                                              pScreen->height, depth,
135                                              BitsPerPixel(depth),
136                                              PixmapBytePad(width, depth),
137                                              pbits))
138             return FALSE;
139         pScrPriv->layer[i].u.run.pixmap = pPixmap;
140         RegionInit(&pScrPriv->layer[i].u.run.region, &box, 0);
141     }
142     pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap;
143     return TRUE;
144 }
145 
146 void
fbOverlayPaintKey(DrawablePtr pDrawable,RegionPtr pRegion,CARD32 pixel,int layer)147 fbOverlayPaintKey(DrawablePtr pDrawable,
148                   RegionPtr pRegion, CARD32 pixel, int layer)
149 {
150     fbFillRegionSolid(pDrawable, pRegion, 0,
151                       fbReplicatePixel(pixel, pDrawable->bitsPerPixel));
152 }
153 
154 /*
155  * Track visible region for each layer
156  */
157 void
fbOverlayUpdateLayerRegion(ScreenPtr pScreen,int layer,RegionPtr prgn)158 fbOverlayUpdateLayerRegion(ScreenPtr pScreen, int layer, RegionPtr prgn)
159 {
160     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
161     int i;
162     RegionRec rgnNew;
163 
164     if (!prgn || !RegionNotEmpty(prgn))
165         return;
166     for (i = 0; i < pScrPriv->nlayers; i++) {
167         if (i == layer) {
168             /* add new piece to this fb */
169             RegionUnion(&pScrPriv->layer[i].u.run.region,
170                         &pScrPriv->layer[i].u.run.region, prgn);
171         }
172         else if (RegionNotEmpty(&pScrPriv->layer[i].u.run.region)) {
173             /* paint new piece with chroma key */
174             RegionNull(&rgnNew);
175             RegionIntersect(&rgnNew, prgn, &pScrPriv->layer[i].u.run.region);
176             (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable,
177                                    &rgnNew, pScrPriv->layer[i].key, i);
178             RegionUninit(&rgnNew);
179             /* remove piece from other fbs */
180             RegionSubtract(&pScrPriv->layer[i].u.run.region,
181                            &pScrPriv->layer[i].u.run.region, prgn);
182         }
183     }
184 }
185 
186 /*
187  * Copy only areas in each layer containing real bits
188  */
189 void
fbOverlayCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)190 fbOverlayCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
191 {
192     ScreenPtr pScreen = pWin->drawable.pScreen;
193     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
194     RegionRec rgnDst;
195     int dx, dy;
196     int i;
197     RegionRec layerRgn[FB_OVERLAY_MAX];
198     PixmapPtr pPixmap;
199 
200     dx = ptOldOrg.x - pWin->drawable.x;
201     dy = ptOldOrg.y - pWin->drawable.y;
202 
203     /*
204      * Clip to existing bits
205      */
206     RegionTranslate(prgnSrc, -dx, -dy);
207     RegionNull(&rgnDst);
208     RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
209     RegionTranslate(&rgnDst, dx, dy);
210     /*
211      * Compute the portion of each fb affected by this copy
212      */
213     for (i = 0; i < pScrPriv->nlayers; i++) {
214         RegionNull(&layerRgn[i]);
215         RegionIntersect(&layerRgn[i], &rgnDst,
216                         &pScrPriv->layer[i].u.run.region);
217         if (RegionNotEmpty(&layerRgn[i])) {
218             RegionTranslate(&layerRgn[i], -dx, -dy);
219             pPixmap = pScrPriv->layer[i].u.run.pixmap;
220             miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
221                          0,
222                          &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0,
223                          (void *) (long) i);
224         }
225     }
226     /*
227      * Update regions
228      */
229     for (i = 0; i < pScrPriv->nlayers; i++) {
230         if (RegionNotEmpty(&layerRgn[i]))
231             fbOverlayUpdateLayerRegion(pScreen, i, &layerRgn[i]);
232 
233         RegionUninit(&layerRgn[i]);
234     }
235     RegionUninit(&rgnDst);
236 }
237 
238 void
fbOverlayWindowExposures(WindowPtr pWin,RegionPtr prgn)239 fbOverlayWindowExposures(WindowPtr pWin, RegionPtr prgn)
240 {
241     fbOverlayUpdateLayerRegion(pWin->drawable.pScreen,
242                                fbOverlayWindowLayer(pWin), prgn);
243     miWindowExposures(pWin, prgn);
244 }
245 
246 Bool
fbOverlaySetupScreen(ScreenPtr pScreen,void * pbits1,void * pbits2,int xsize,int ysize,int dpix,int dpiy,int width1,int width2,int bpp1,int bpp2)247 fbOverlaySetupScreen(ScreenPtr pScreen,
248                      void *pbits1,
249                      void *pbits2,
250                      int xsize,
251                      int ysize,
252                      int dpix,
253                      int dpiy, int width1, int width2, int bpp1, int bpp2)
254 {
255     return fbSetupScreen(pScreen,
256                          pbits1, xsize, ysize, dpix, dpiy, width1, bpp1);
257 }
258 
259 Bool
fbOverlayFinishScreenInit(ScreenPtr pScreen,void * pbits1,void * pbits2,int xsize,int ysize,int dpix,int dpiy,int width1,int width2,int bpp1,int bpp2,int depth1,int depth2)260 fbOverlayFinishScreenInit(ScreenPtr pScreen,
261                           void *pbits1,
262                           void *pbits2,
263                           int xsize,
264                           int ysize,
265                           int dpix,
266                           int dpiy,
267                           int width1,
268                           int width2,
269                           int bpp1, int bpp2, int depth1, int depth2)
270 {
271     VisualPtr visuals;
272     DepthPtr depths;
273     int nvisuals;
274     int ndepths;
275     VisualID defaultVisual;
276     FbOverlayScrPrivPtr pScrPriv;
277 
278     if (!dixRegisterPrivateKey
279         (&fbOverlayScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
280         return FALSE;
281 
282     if (bpp1 == 24 || bpp2 == 24)
283         return FALSE;
284 
285     pScrPriv = malloc(sizeof(FbOverlayScrPrivRec));
286     if (!pScrPriv)
287         return FALSE;
288 
289     if (!fbInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &depth1,
290                        &defaultVisual, ((unsigned long) 1 << (bpp1 - 1)) |
291                        ((unsigned long) 1 << (bpp2 - 1)), 8)) {
292         free(pScrPriv);
293         return FALSE;
294     }
295     if (!miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0,
296                       depth1, ndepths, depths,
297                       defaultVisual, nvisuals, visuals)) {
298         free(pScrPriv);
299         return FALSE;
300     }
301     /* MI thinks there's no frame buffer */
302 #ifdef MITSHM
303     ShmRegisterFbFuncs(pScreen);
304 #endif
305     pScreen->minInstalledCmaps = 1;
306     pScreen->maxInstalledCmaps = 2;
307 
308     pScrPriv->nlayers = 2;
309     pScrPriv->PaintKey = fbOverlayPaintKey;
310     pScrPriv->CopyWindow = fbCopyWindowProc;
311     pScrPriv->layer[0].u.init.pbits = pbits1;
312     pScrPriv->layer[0].u.init.width = width1;
313     pScrPriv->layer[0].u.init.depth = depth1;
314 
315     pScrPriv->layer[1].u.init.pbits = pbits2;
316     pScrPriv->layer[1].u.init.width = width2;
317     pScrPriv->layer[1].u.init.depth = depth2;
318     dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv);
319 
320     /* overwrite miCloseScreen with our own */
321     pScreen->CloseScreen = fbOverlayCloseScreen;
322     pScreen->CreateScreenResources = fbOverlayCreateScreenResources;
323     pScreen->CreateWindow = fbOverlayCreateWindow;
324     pScreen->WindowExposures = fbOverlayWindowExposures;
325     pScreen->CopyWindow = fbOverlayCopyWindow;
326 
327     return TRUE;
328 }
329