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