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
35static DevPrivateKeyRec fbOverlayScreenPrivateKeyRec;
36
37#define fbOverlayScreenPrivateKey (&fbOverlayScreenPrivateKeyRec)
38
39DevPrivateKey
40fbOverlayGetScreenPrivateKey(void)
41{
42    return fbOverlayScreenPrivateKey;
43}
44
45/*
46 * Replace this if you want something supporting
47 * multiple overlays with the same depth
48 */
49Bool
50fbOverlayCreateWindow(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
79Bool
80fbOverlayCloseScreen(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 */
95int
96fbOverlayWindowLayer(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
108Bool
109fbOverlayCreateScreenResources(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
146void
147fbOverlayPaintKey(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 */
157void
158fbOverlayUpdateLayerRegion(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 */
189void
190fbOverlayCopyWindow(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
238void
239fbOverlayWindowExposures(WindowPtr pWin, RegionPtr prgn)
240{
241    fbOverlayUpdateLayerRegion(pWin->drawable.pScreen,
242                               fbOverlayWindowLayer(pWin), prgn);
243    miWindowExposures(pWin, prgn);
244}
245
246Bool
247fbOverlaySetupScreen(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
259Bool
260fbOverlayFinishScreenInit(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