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