1 /*
2  * Copyright © 2001 Keith Packard
3  *
4  * Partly based on code that is Copyright © The XFree86 Project Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 /** @file
26  * This file covers the initialization and teardown of SAA, and has various
27  * functions not responsible for performing rendering, pixmap migration, or
28  * memory management.
29  */
30 
31 #ifdef HAVE_DIX_CONFIG_H
32 #include <dix-config.h>
33 #endif
34 
35 #include <stdlib.h>
36 
37 #include "saa_priv.h"
38 #include <X11/fonts/fontstruct.h>
39 #include "regionstr.h"
40 #include "saa.h"
41 #include "saa_priv.h"
42 
43 #ifdef SAA_DEVPRIVATEKEYREC
44 DevPrivateKeyRec saa_screen_index;
45 DevPrivateKeyRec saa_pixmap_index;
46 DevPrivateKeyRec saa_gc_index;
47 #else
48 int saa_screen_index = -1;
49 int saa_pixmap_index = -1;
50 int saa_gc_index = -1;
51 #endif
52 
53 /**
54  * saa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
55  *
56  * @param pDrawable the drawable being requested.
57  *
58  * This function returns the backing pixmap for a drawable, whether it is a
59  * redirected window, unredirected window, or already a pixmap.  Note that
60  * coordinate translation is needed when drawing to the backing pixmap of a
61  * redirected window, and the translation coordinates are provided by calling
62  * saa_get_drawable_pixmap() on the drawable.
63  */
64 PixmapPtr
saa_get_drawable_pixmap(DrawablePtr pDrawable)65 saa_get_drawable_pixmap(DrawablePtr pDrawable)
66 {
67     if (pDrawable->type == DRAWABLE_WINDOW)
68 	return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
69     else
70 	return (PixmapPtr) pDrawable;
71 }
72 
73 /**
74  * Sets the offsets to add to coordinates to make them address the same bits in
75  * the backing drawable. These coordinates are nonzero only for redirected
76  * windows.
77  */
78 void
saa_get_drawable_deltas(DrawablePtr pDrawable,PixmapPtr pPixmap,int * xp,int * yp)79 saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
80 			int *xp, int *yp)
81 {
82 #ifdef COMPOSITE
83     if (pDrawable->type == DRAWABLE_WINDOW) {
84 	*xp = -pPixmap->screen_x;
85 	*yp = -pPixmap->screen_y;
86 	return;
87     }
88 #endif
89 
90     *xp = 0;
91     *yp = 0;
92 }
93 
94 /**
95  * Returns the pixmap which backs a drawable, and the offsets to add to
96  * coordinates to make them address the same bits in the backing drawable.
97  */
98 PixmapPtr
saa_get_pixmap(DrawablePtr drawable,int * xp,int * yp)99 saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp)
100 {
101     PixmapPtr pixmap = saa_get_drawable_pixmap(drawable);
102 
103     saa_get_drawable_deltas(drawable, pixmap, xp, yp);
104 
105     return pixmap;
106 }
107 
108 static Bool
saa_download_from_hw(PixmapPtr pix,RegionPtr readback)109 saa_download_from_hw(PixmapPtr pix, RegionPtr readback)
110 {
111     struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
112     struct saa_driver *driver = sscreen->driver;
113     struct saa_pixmap *spix = saa_pixmap(pix);
114     void *addr;
115     Bool ret;
116 
117     if (spix->mapped_access)
118 	driver->release_from_cpu(driver, pix, spix->mapped_access);
119 
120     ret = driver->download_from_hw(driver, pix, readback);
121 
122     if (spix->mapped_access) {
123 	addr = driver->sync_for_cpu(driver, pix, spix->mapped_access);
124 	if (addr != NULL)
125 	    spix->addr = addr;
126     }
127 
128     return ret;
129 }
130 
131 Bool
saa_prepare_access_pixmap(PixmapPtr pix,saa_access_t access,RegionPtr read_reg)132 saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
133 			  RegionPtr read_reg)
134 {
135     ScreenPtr pScreen = pix->drawable.pScreen;
136     struct saa_screen_priv *sscreen = saa_screen(pScreen);
137     struct saa_driver *driver = sscreen->driver;
138     struct saa_pixmap *spix = saa_pixmap(pix);
139     saa_access_t map_access = 0;
140     Bool ret = TRUE;
141 
142     if (read_reg && REGION_NOTEMPTY(pScreen, read_reg))
143 	ret = saa_download_from_hw(pix, read_reg);
144 
145     if (!ret) {
146 	LogMessage(X_ERROR, "Prepare access pixmap failed.\n");
147 	return ret;
148     }
149 
150     if ((access & SAA_ACCESS_R) != 0 && spix->read_access++ == 0)
151 	map_access = SAA_ACCESS_R;
152     if ((access & SAA_ACCESS_W) != 0 && spix->write_access++ == 0)
153 	map_access |= SAA_ACCESS_W;
154 
155     if (map_access) {
156 	if (spix->auth_loc != saa_loc_override) {
157 	    (void)driver->sync_for_cpu(driver, pix, map_access);
158 	    spix->addr = driver->map(driver, pix, map_access);
159 	} else
160 	    spix->addr = spix->override;
161 	spix->mapped_access |= map_access;
162     }
163 
164     pix->devPrivate.ptr = spix->addr;
165     return TRUE;
166 }
167 
168 void
saa_finish_access_pixmap(PixmapPtr pix,saa_access_t access)169 saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access)
170 {
171     struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
172     struct saa_driver *driver = sscreen->driver;
173     struct saa_pixmap *spix = saa_pixmap(pix);
174     saa_access_t unmap_access = 0;
175 
176     if ((access & SAA_ACCESS_R) != 0 && --spix->read_access == 0)
177 	unmap_access = SAA_ACCESS_R;
178     if ((access & SAA_ACCESS_W) != 0 && --spix->write_access == 0)
179 	unmap_access |= SAA_ACCESS_W;
180 
181     if (spix->read_access < 0)
182 	LogMessage(X_ERROR, "Incorrect read access.\n");
183     if (spix->write_access < 0)
184 	LogMessage(X_ERROR, "Incorrect write access.\n");
185 
186     if (unmap_access) {
187 	if (spix->auth_loc != saa_loc_override) {
188 	    driver->unmap(driver, pix, unmap_access);
189 	    driver->release_from_cpu(driver, pix, unmap_access);
190 	}
191 	spix->mapped_access &= ~unmap_access;
192     }
193     if (!spix->mapped_access) {
194 	spix->addr = NULL;
195 	pix->devPrivate.ptr = SAA_INVALID_ADDRESS;
196     }
197 }
198 
199 /*
200  * Callback that is called after a rendering operation. We try to
201  * determine whether it's a shadow damage or a hw damage and call the
202  * driver callback.
203  */
204 
205 static void
saa_report_damage(DamagePtr damage,RegionPtr reg,void * closure)206 saa_report_damage(DamagePtr damage, RegionPtr reg, void *closure)
207 {
208     PixmapPtr pixmap = (PixmapPtr) closure;
209     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
210     struct saa_driver *driver = saa_screen(pixmap->drawable.pScreen)->driver;
211 
212     if (spix->read_access || spix->write_access)
213 	LogMessage(X_ERROR, "Damage report inside prepare access.\n");
214 
215     driver->operation_complete(driver, pixmap);
216     DamageEmpty(damage);
217 }
218 
219 Bool
saa_add_damage(PixmapPtr pixmap)220 saa_add_damage(PixmapPtr pixmap)
221 {
222     ScreenPtr pScreen = pixmap->drawable.pScreen;
223     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
224 
225     if (spix->damage)
226 	return TRUE;
227 
228     spix->damage = DamageCreate(saa_report_damage, NULL,
229 				DamageReportRawRegion, TRUE, pScreen, pixmap);
230     if (!spix->damage)
231 	return FALSE;
232 
233     DamageRegister(&pixmap->drawable, spix->damage);
234     DamageSetReportAfterOp(spix->damage, TRUE);
235 
236     return TRUE;
237 }
238 
239 static inline RegionPtr
saa_pix_damage_region(struct saa_pixmap * spix)240 saa_pix_damage_region(struct saa_pixmap *spix)
241 {
242     return (spix->damage ? DamageRegion(spix->damage) : NULL);
243 }
244 
245 Bool
saa_pad_read(DrawablePtr draw)246 saa_pad_read(DrawablePtr draw)
247 {
248     ScreenPtr pScreen = draw->pScreen;
249     PixmapPtr pix;
250     int xp;
251     int yp;
252     BoxRec box;
253     RegionRec entire;
254     Bool ret;
255 
256     (void)pScreen;
257     pix = saa_get_pixmap(draw, &xp, &yp);
258 
259     box.x1 = draw->x + xp;
260     box.y1 = draw->y + yp;
261     box.x2 = box.x1 + draw->width;
262     box.y2 = box.y1 + draw->height;
263 
264     REGION_INIT(pScreen, &entire, &box, 1);
265     ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
266     REGION_UNINIT(pScreen, &entire);
267     return ret;
268 }
269 
270 Bool
saa_pad_read_box(DrawablePtr draw,int x,int y,int w,int h)271 saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h)
272 {
273     ScreenPtr pScreen = draw->pScreen;
274     PixmapPtr pix;
275     int xp;
276     int yp;
277     BoxRec box;
278     RegionRec entire;
279     Bool ret;
280 
281     (void)pScreen;
282     pix = saa_get_pixmap(draw, &xp, &yp);
283 
284     box.x1 = x + xp;
285     box.y1 = y + yp;
286     box.x2 = box.x1 + w;
287     box.y2 = box.y1 + h;
288 
289     REGION_INIT(pScreen, &entire, &box, 1);
290     ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
291     REGION_UNINIT(pScreen, &entire);
292     return ret;
293 }
294 
295 /**
296  * Prepares a drawable destination for access, and maps it read-write.
297  * If check_read is TRUE, pGC should point to a valid GC. The drawable
298  * may then be mapped write-only if the pending operation admits.
299  */
300 
301 Bool
saa_pad_write(DrawablePtr draw,GCPtr pGC,Bool check_read,saa_access_t * access)302 saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
303 	      saa_access_t * access)
304 {
305     int xp;
306     int yp;
307     PixmapPtr pixmap = saa_get_pixmap(draw, &xp, &yp);
308     struct saa_pixmap *spix = saa_pixmap(pixmap);
309 
310     *access = SAA_ACCESS_W;
311 
312     /*
313      * If the to-be-damaged area doesn't depend at all on previous
314      * rendered contents, we don't need to do any readback.
315      */
316 
317     if (check_read && !saa_gc_reads_destination(draw, pGC))
318 	return saa_prepare_access_pixmap(pixmap, *access, NULL);
319 
320     *access |= SAA_ACCESS_R;
321 
322     /*
323      * Read back the area to be damaged.
324      */
325 
326     return saa_prepare_access_pixmap(pixmap, *access,
327 				     saa_pix_damage_pending(spix));
328 }
329 
330 void
saa_fad_read(DrawablePtr draw)331 saa_fad_read(DrawablePtr draw)
332 {
333     saa_finish_access_pixmap(saa_get_drawable_pixmap(draw), SAA_ACCESS_R);
334 }
335 
336 void
saa_fad_write(DrawablePtr draw,saa_access_t access)337 saa_fad_write(DrawablePtr draw, saa_access_t access)
338 {
339     PixmapPtr pix = saa_get_drawable_pixmap(draw);
340     struct saa_pixmap *spix = saa_pixmap(pix);
341 
342     saa_finish_access_pixmap(pix, access);
343     if (spix->damage)
344 	saa_pixmap_dirty(pix, FALSE, saa_pix_damage_pending(spix));
345 }
346 
347 Bool
saa_gc_reads_destination(DrawablePtr pDrawable,GCPtr pGC)348 saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC)
349 {
350     return ((pGC->alu != GXcopy && pGC->alu != GXclear && pGC->alu != GXset &&
351 	     pGC->alu != GXcopyInverted) || pGC->fillStyle == FillStippled ||
352 	    pGC->clientClip != NULL ||
353 	    !SAA_PM_IS_SOLID(pDrawable, pGC->planemask));
354 }
355 
356 Bool
saa_op_reads_destination(CARD8 op)357 saa_op_reads_destination(CARD8 op)
358 {
359     /* FALSE (does not read destination) is the list of ops in the protocol
360      * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
361      * That's just Clear and Src.  ReduceCompositeOp() will already have
362      * converted con/disjoint clear/src to Clear or Src.
363      */
364     switch (op) {
365     case PictOpClear:
366     case PictOpSrc:
367 	return FALSE;
368     default:
369 	return TRUE;
370     }
371 }
372 
373 static void
saa_validate_gc(GCPtr pGC,unsigned long changes,DrawablePtr pDrawable)374 saa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
375 {
376     /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
377      * Do a few smart things so fbValidateGC can do it's work.
378      */
379 
380     ScreenPtr pScreen = pDrawable->pScreen;
381     struct saa_screen_priv *sscreen = saa_screen(pScreen);
382     struct saa_gc_priv *sgc = saa_gc(pGC);
383     PixmapPtr pTile = NULL;
384     Bool finish_current_tile = FALSE;
385 
386     /* Either of these conditions is enough to trigger access to a tile pixmap. */
387     /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
388     if (pGC->fillStyle == FillTiled
389 	|| ((changes & GCTile) && !pGC->tileIsPixel)) {
390 	pTile = pGC->tile.pixmap;
391 
392 	/* Sometimes tile pixmaps are swapped, you need access to:
393 	 * - The current tile if it depth matches.
394 	 * - Or the rotated tile if that one matches depth and !(changes & GCTile).
395 	 * - Or the current tile pixmap and a newly created one.
396 	 */
397 	if (pTile && pTile->drawable.depth != pDrawable->depth
398 	    && !(changes & GCTile)) {
399 	    PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
400 
401 	    if (pRotatedTile
402 		&& pRotatedTile->drawable.depth == pDrawable->depth)
403 		pTile = pRotatedTile;
404 	    else
405 		finish_current_tile = TRUE;	/* CreatePixmap will be called. */
406 	}
407     }
408 
409     if (pGC->stipple && !saa_pad_read(&pGC->stipple->drawable)) {
410 	LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
411 	return;
412     }
413 
414     if (pTile && !saa_pad_read(&pTile->drawable)) {
415 	LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
416 	goto out_no_tile;
417     }
418 
419     /* Calls to Create/DestroyPixmap have to be identified as special, so
420      * up sscreen->fallback_count.
421      */
422 
423     sscreen->fallback_count++;
424     saa_swap(sgc, pGC, funcs);
425     (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
426     saa_swap(sgc, pGC, funcs);
427 
428     if (finish_current_tile && pGC->tile.pixmap)
429 	saa_fad_write(&pGC->tile.pixmap->drawable, SAA_ACCESS_W);
430     sscreen->fallback_count--;
431 
432     if (pTile)
433 	saa_fad_read(&pTile->drawable);
434  out_no_tile:
435     if (pGC->stipple)
436 	saa_fad_read(&pGC->stipple->drawable);
437 }
438 
439 static void
saa_destroy_gc(GCPtr pGC)440 saa_destroy_gc(GCPtr pGC)
441 {
442     struct saa_gc_priv *sgc = saa_gc(pGC);
443 
444     saa_swap(sgc, pGC, funcs);
445     (*pGC->funcs->DestroyGC) (pGC);
446     saa_swap(sgc, pGC, funcs);
447 }
448 
449 static void
saa_change_gc(GCPtr pGC,unsigned long mask)450 saa_change_gc(GCPtr pGC, unsigned long mask)
451 {
452     struct saa_gc_priv *sgc = saa_gc(pGC);
453 
454     saa_swap(sgc, pGC, funcs);
455     (*pGC->funcs->ChangeGC) (pGC, mask);
456     saa_swap(sgc, pGC, funcs);
457 }
458 
459 static void
saa_copy_gc(GCPtr pGCSrc,unsigned long mask,GCPtr pGCDst)460 saa_copy_gc(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
461 {
462     struct saa_gc_priv *sgc = saa_gc(pGCDst);
463 
464     saa_swap(sgc, pGCDst, funcs);
465     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
466     saa_swap(sgc, pGCDst, funcs);
467 }
468 
469 static void
saa_change_clip(GCPtr pGC,int type,pointer pvalue,int nrects)470 saa_change_clip(GCPtr pGC, int type, pointer pvalue, int nrects)
471 {
472     struct saa_gc_priv *sgc = saa_gc(pGC);
473 
474     saa_swap(sgc, pGC, funcs);
475     (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
476     saa_swap(sgc, pGC, funcs);
477 }
478 
479 static void
saa_copy_clip(GCPtr pGCDst,GCPtr pGCSrc)480 saa_copy_clip(GCPtr pGCDst, GCPtr pGCSrc)
481 {
482     struct saa_gc_priv *sgc = saa_gc(pGCDst);
483 
484     saa_swap(sgc, pGCDst, funcs);
485     (*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
486     saa_swap(sgc, pGCDst, funcs);
487 }
488 
489 static void
saa_destroy_clip(GCPtr pGC)490 saa_destroy_clip(GCPtr pGC)
491 {
492     struct saa_gc_priv *sgc = saa_gc(pGC);
493 
494     saa_swap(sgc, pGC, funcs);
495     (*pGC->funcs->DestroyClip) (pGC);
496     saa_swap(sgc, pGC, funcs);
497 }
498 
499 static GCFuncs saa_gc_funcs = {
500     saa_validate_gc,
501     saa_change_gc,
502     saa_copy_gc,
503     saa_destroy_gc,
504     saa_change_clip,
505     saa_destroy_clip,
506     saa_copy_clip
507 };
508 
509 /**
510  * saa_create_gc makes a new GC and hooks up its funcs handler, so that
511  * saa_validate_gc() will get called.
512  */
513 int
saa_create_gc(GCPtr pGC)514 saa_create_gc(GCPtr pGC)
515 {
516     ScreenPtr pScreen = pGC->pScreen;
517     struct saa_screen_priv *sscreen = saa_screen(pScreen);
518     struct saa_gc_priv *sgc = saa_gc(pGC);
519     Bool ret;
520 
521     saa_swap(sscreen, pScreen, CreateGC);
522     ret = pScreen->CreateGC(pGC);
523     if (ret) {
524 	saa_wrap(sgc, pGC, funcs, &saa_gc_funcs);
525 	saa_wrap(sgc, pGC, ops, &saa_gc_ops);
526     }
527     saa_swap(sscreen, pScreen, CreateGC);
528 
529     return ret;
530 }
531 
532 static Bool
saa_prepare_access_window(WindowPtr pWin)533 saa_prepare_access_window(WindowPtr pWin)
534 {
535     if (pWin->backgroundState == BackgroundPixmap) {
536 	if (!saa_pad_read(&pWin->background.pixmap->drawable))
537 	    return FALSE;
538     }
539 
540     if (pWin->borderIsPixel == FALSE) {
541 	if (!saa_pad_read(&pWin->border.pixmap->drawable)) {
542 	    if (pWin->backgroundState == BackgroundPixmap)
543 		saa_fad_read(&pWin->background.pixmap->drawable);
544 	    return FALSE;
545 	}
546     }
547     return TRUE;
548 }
549 
550 static void
saa_finish_access_window(WindowPtr pWin)551 saa_finish_access_window(WindowPtr pWin)
552 {
553     if (pWin->backgroundState == BackgroundPixmap)
554 	saa_fad_read(&pWin->background.pixmap->drawable);
555 
556     if (pWin->borderIsPixel == FALSE)
557 	saa_fad_read(&pWin->border.pixmap->drawable);
558 }
559 
560 static Bool
saa_change_window_attributes(WindowPtr pWin,unsigned long mask)561 saa_change_window_attributes(WindowPtr pWin, unsigned long mask)
562 {
563     Bool ret;
564 
565     if (!saa_prepare_access_window(pWin))
566 	return FALSE;
567     ret = fbChangeWindowAttributes(pWin, mask);
568     saa_finish_access_window(pWin);
569     return ret;
570 }
571 
572 RegionPtr
saa_bitmap_to_region(PixmapPtr pPix)573 saa_bitmap_to_region(PixmapPtr pPix)
574 {
575     RegionPtr ret;
576 
577     if (!saa_pad_read(&pPix->drawable))
578 	return NULL;
579     ret = fbPixmapToRegion(pPix);
580     saa_fad_read(&pPix->drawable);
581     return ret;
582 }
583 
584 void
saa_set_fallback_debug(ScreenPtr screen,Bool enable)585 saa_set_fallback_debug(ScreenPtr screen, Bool enable)
586 {
587     struct saa_screen_priv *sscreen = saa_screen(screen);
588 
589     sscreen->fallback_debug = enable;
590 }
591 
592 /**
593  * saa_close_screen() unwraps its wrapped screen functions and tears down SAA's
594  * screen private, before calling down to the next CloseScreen.
595  */
596 Bool
saa_close_screen(CLOSE_SCREEN_ARGS_DECL)597 saa_close_screen(CLOSE_SCREEN_ARGS_DECL)
598 {
599     struct saa_screen_priv *sscreen = saa_screen(pScreen);
600     struct saa_driver *driver = sscreen->driver;
601 
602     if (pScreen->devPrivate) {
603 	/* Destroy the pixmap created by miScreenInit() *before*
604 	 * chaining up as we finalize ourselves here and so this
605 	 * is the last chance we have of releasing our resources
606 	 * associated with the Pixmap. So do it first.
607 	 */
608 	(void)(*pScreen->DestroyPixmap) (pScreen->devPrivate);
609 	pScreen->devPrivate = NULL;
610     }
611 
612     saa_unwrap(sscreen, pScreen, CloseScreen);
613     saa_unwrap(sscreen, pScreen, CreateGC);
614     saa_unwrap(sscreen, pScreen, ChangeWindowAttributes);
615     saa_unwrap(sscreen, pScreen, CreatePixmap);
616     saa_unwrap(sscreen, pScreen, DestroyPixmap);
617     saa_unwrap(sscreen, pScreen, ModifyPixmapHeader);
618     saa_unwrap(sscreen, pScreen, BitmapToRegion);
619 #ifdef RENDER
620     saa_render_takedown(pScreen);
621 #endif
622     saa_unaccel_takedown(pScreen);
623     driver->takedown(driver);
624 
625     free(sscreen);
626 
627     return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
628 }
629 
630 struct saa_driver *
saa_get_driver(ScreenPtr pScreen)631 saa_get_driver(ScreenPtr pScreen)
632 {
633     return saa_screen(pScreen)->driver;
634 }
635 
636 /**
637  * @param pScreen screen being initialized
638  * @param pScreenInfo SAA driver record
639  *
640  * saa_driver_init sets up SAA given a driver record filled in by the driver.
641  * pScreenInfo should have been allocated by saa_driver_alloc().  See the
642  * comments in _SaaDriver for what must be filled in and what is optional.
643  *
644  * @return TRUE if SAA was successfully initialized.
645  */
646 Bool
saa_driver_init(ScreenPtr screen,struct saa_driver * saa_driver)647 saa_driver_init(ScreenPtr screen, struct saa_driver * saa_driver)
648 {
649     struct saa_screen_priv *sscreen;
650 
651     if (!saa_driver)
652 	return FALSE;
653 
654     if (saa_driver->saa_major != SAA_VERSION_MAJOR ||
655 	saa_driver->saa_minor > SAA_VERSION_MINOR) {
656 	LogMessage(X_ERROR,
657 		   "SAA(%d): driver's SAA version requirements "
658 		   "(%d.%d) are incompatible with SAA version (%d.%d)\n",
659 		   screen->myNum, saa_driver->saa_major,
660 		   saa_driver->saa_minor, SAA_VERSION_MAJOR, SAA_VERSION_MINOR);
661 	return FALSE;
662     }
663 #if 0
664     if (!saa_driver->prepare_solid) {
665 	LogMessage(X_ERROR,
666 		   "SAA(%d): saa_driver_t::prepare_solid must be "
667 		   "non-NULL\n", screen->myNum);
668 	return FALSE;
669     }
670 
671     if (!saa_driver->prepare_copy) {
672 	LogMessage(X_ERROR,
673 		   "SAA(%d): saa_driver_t::prepare_copy must be "
674 		   "non-NULL\n", screen->myNum);
675 	return FALSE;
676     }
677 #endif
678 #ifdef SAA_DEVPRIVATEKEYREC
679     if (!dixRegisterPrivateKey(&saa_screen_index, PRIVATE_SCREEN, 0)) {
680 	LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
681 	return FALSE;
682     }
683     if (!dixRegisterPrivateKey(&saa_pixmap_index, PRIVATE_PIXMAP,
684 			       saa_driver->pixmap_size)) {
685 	LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
686 	return FALSE;
687     }
688     if (!dixRegisterPrivateKey(&saa_gc_index, PRIVATE_GC,
689 			       sizeof(struct saa_gc_priv))) {
690 	LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
691 	return FALSE;
692     }
693 #else
694     if (!dixRequestPrivate(&saa_screen_index, 0)) {
695 	LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
696 	return FALSE;
697     }
698     if (!dixRequestPrivate(&saa_pixmap_index, saa_driver->pixmap_size)) {
699 	LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
700 	return FALSE;
701     }
702     if (!dixRequestPrivate(&saa_gc_index, sizeof(struct saa_gc_priv))) {
703 	LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
704 	return FALSE;
705     }
706 #endif
707 
708     sscreen = calloc(1, sizeof(*sscreen));
709 
710     if (!sscreen) {
711 	LogMessage(X_WARNING,
712 		   "SAA(%d): Failed to allocate screen private\n",
713 		   screen->myNum);
714 	return FALSE;
715     }
716 
717     sscreen->driver = saa_driver;
718     dixSetPrivate(&screen->devPrivates, &saa_screen_index, sscreen);
719 
720     /*
721      * Replace various fb screen functions
722      */
723 
724     saa_wrap(sscreen, screen, CloseScreen, saa_close_screen);
725     saa_wrap(sscreen, screen, CreateGC, saa_create_gc);
726     saa_wrap(sscreen, screen, ChangeWindowAttributes,
727 	     saa_change_window_attributes);
728     saa_wrap(sscreen, screen, CreatePixmap, saa_create_pixmap);
729     saa_wrap(sscreen, screen, DestroyPixmap, saa_destroy_pixmap);
730     saa_wrap(sscreen, screen, ModifyPixmapHeader, saa_modify_pixmap_header);
731 
732     saa_wrap(sscreen, screen, BitmapToRegion, saa_bitmap_to_region);
733     saa_unaccel_setup(screen);
734 #ifdef RENDER
735     saa_render_setup(screen);
736 #endif
737 
738     return TRUE;
739 }
740 
741 Bool
saa_resources_init(ScreenPtr screen)742 saa_resources_init(ScreenPtr screen)
743 {
744 /*    if (!saa_glyphs_init(screen))
745 	return FALSE;
746 */
747     return TRUE;
748 }
749