saa.c revision 25dbecb6
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
44DevPrivateKeyRec saa_screen_index;
45DevPrivateKeyRec saa_pixmap_index;
46DevPrivateKeyRec saa_gc_index;
47#else
48int saa_screen_index = -1;
49int saa_pixmap_index = -1;
50int 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 */
64PixmapPtr
65saa_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 */
78void
79saa_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 */
98PixmapPtr
99saa_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
108static Bool
109saa_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
131Bool
132saa_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
168void
169saa_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
205static void
206saa_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/**
220 * saa_notify_destroy_damage - Handle destroy damage notification
221 *
222 * \param damage[in] damage Pointer to damage about to be destroyed
223 * \param closure[in] closure Closure.
224 *
225 * Makes sure that whatever code destroys a damage object clears the
226 * saa_pixmap damage pointer. This is extra protection. Typically
227 * saa_destroy_pixmap should be correct if the various subsystem
228 * DestroyPixmap functions are called in the right order.
229 */
230static void
231saa_notify_destroy_damage(DamagePtr damage, void *closure)
232{
233    PixmapPtr pixmap = (PixmapPtr) closure;
234    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
235
236    if (spix->damage == damage)
237	spix->damage = NULL;
238}
239
240Bool
241saa_add_damage(PixmapPtr pixmap)
242{
243    ScreenPtr pScreen = pixmap->drawable.pScreen;
244    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
245
246    if (spix->damage)
247	return TRUE;
248
249    spix->damage = DamageCreate(saa_report_damage, saa_notify_destroy_damage,
250				DamageReportRawRegion, TRUE, pScreen, pixmap);
251    if (!spix->damage)
252	return FALSE;
253
254    DamageRegister(&pixmap->drawable, spix->damage);
255    DamageSetReportAfterOp(spix->damage, TRUE);
256
257    return TRUE;
258}
259
260static inline RegionPtr
261saa_pix_damage_region(struct saa_pixmap *spix)
262{
263    return (spix->damage ? DamageRegion(spix->damage) : NULL);
264}
265
266Bool
267saa_pad_read(DrawablePtr draw)
268{
269    ScreenPtr pScreen = draw->pScreen;
270    PixmapPtr pix;
271    int xp;
272    int yp;
273    BoxRec box;
274    RegionRec entire;
275    Bool ret;
276
277    (void)pScreen;
278    pix = saa_get_pixmap(draw, &xp, &yp);
279
280    box.x1 = draw->x + xp;
281    box.y1 = draw->y + yp;
282    box.x2 = box.x1 + draw->width;
283    box.y2 = box.y1 + draw->height;
284
285    REGION_INIT(pScreen, &entire, &box, 1);
286    ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
287    REGION_UNINIT(pScreen, &entire);
288    return ret;
289}
290
291Bool
292saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h)
293{
294    ScreenPtr pScreen = draw->pScreen;
295    PixmapPtr pix;
296    int xp;
297    int yp;
298    BoxRec box;
299    RegionRec entire;
300    Bool ret;
301
302    (void)pScreen;
303    pix = saa_get_pixmap(draw, &xp, &yp);
304
305    box.x1 = x + xp;
306    box.y1 = y + yp;
307    box.x2 = box.x1 + w;
308    box.y2 = box.y1 + h;
309
310    REGION_INIT(pScreen, &entire, &box, 1);
311    ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
312    REGION_UNINIT(pScreen, &entire);
313    return ret;
314}
315
316/**
317 * Prepares a drawable destination for access, and maps it read-write.
318 * If check_read is TRUE, pGC should point to a valid GC. The drawable
319 * may then be mapped write-only if the pending operation admits.
320 */
321
322Bool
323saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
324	      saa_access_t * access)
325{
326    int xp;
327    int yp;
328    PixmapPtr pixmap = saa_get_pixmap(draw, &xp, &yp);
329    struct saa_pixmap *spix = saa_pixmap(pixmap);
330
331    *access = SAA_ACCESS_W;
332
333    /*
334     * If the to-be-damaged area doesn't depend at all on previous
335     * rendered contents, we don't need to do any readback.
336     */
337
338    if (check_read && !saa_gc_reads_destination(draw, pGC))
339	return saa_prepare_access_pixmap(pixmap, *access, NULL);
340
341    *access |= SAA_ACCESS_R;
342
343    /*
344     * Read back the area to be damaged.
345     */
346
347    return saa_prepare_access_pixmap(pixmap, *access,
348				     saa_pix_damage_pending(spix));
349}
350
351void
352saa_fad_read(DrawablePtr draw)
353{
354    saa_finish_access_pixmap(saa_get_drawable_pixmap(draw), SAA_ACCESS_R);
355}
356
357void
358saa_fad_write(DrawablePtr draw, saa_access_t access)
359{
360    PixmapPtr pix = saa_get_drawable_pixmap(draw);
361    struct saa_pixmap *spix = saa_pixmap(pix);
362
363    saa_finish_access_pixmap(pix, access);
364    if (spix->damage)
365	saa_pixmap_dirty(pix, FALSE, saa_pix_damage_pending(spix));
366}
367
368Bool
369saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC)
370{
371    return ((pGC->alu != GXcopy && pGC->alu != GXclear && pGC->alu != GXset &&
372	     pGC->alu != GXcopyInverted) || pGC->fillStyle == FillStippled ||
373	    pGC->clientClip != NULL ||
374	    !SAA_PM_IS_SOLID(pDrawable, pGC->planemask));
375}
376
377Bool
378saa_op_reads_destination(CARD8 op)
379{
380    /* FALSE (does not read destination) is the list of ops in the protocol
381     * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
382     * That's just Clear and Src.  ReduceCompositeOp() will already have
383     * converted con/disjoint clear/src to Clear or Src.
384     */
385    switch (op) {
386    case PictOpClear:
387    case PictOpSrc:
388	return FALSE;
389    default:
390	return TRUE;
391    }
392}
393
394static void
395saa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
396{
397    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
398     * Do a few smart things so fbValidateGC can do it's work.
399     */
400
401    ScreenPtr pScreen = pDrawable->pScreen;
402    struct saa_screen_priv *sscreen = saa_screen(pScreen);
403    struct saa_gc_priv *sgc = saa_gc(pGC);
404    PixmapPtr pTile = NULL;
405    Bool finish_current_tile = FALSE;
406
407    /* Either of these conditions is enough to trigger access to a tile pixmap. */
408    /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
409    if (pGC->fillStyle == FillTiled
410	|| ((changes & GCTile) && !pGC->tileIsPixel)) {
411	pTile = pGC->tile.pixmap;
412
413	/* Sometimes tile pixmaps are swapped, you need access to:
414	 * - The current tile if it depth matches.
415	 * - Or the rotated tile if that one matches depth and !(changes & GCTile).
416	 * - Or the current tile pixmap and a newly created one.
417	 */
418	if (pTile && pTile->drawable.depth != pDrawable->depth
419	    && !(changes & GCTile)) {
420	    PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
421
422	    if (pRotatedTile
423		&& pRotatedTile->drawable.depth == pDrawable->depth)
424		pTile = pRotatedTile;
425	    else
426		finish_current_tile = TRUE;	/* CreatePixmap will be called. */
427	}
428    }
429
430    if (pGC->stipple && !saa_pad_read(&pGC->stipple->drawable)) {
431	LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
432	return;
433    }
434
435    if (pTile && !saa_pad_read(&pTile->drawable)) {
436	LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
437	goto out_no_tile;
438    }
439
440    /* Calls to Create/DestroyPixmap have to be identified as special, so
441     * up sscreen->fallback_count.
442     */
443
444    sscreen->fallback_count++;
445    saa_swap(sgc, pGC, funcs);
446    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
447    saa_swap(sgc, pGC, funcs);
448
449    if (finish_current_tile && pGC->tile.pixmap)
450	saa_fad_write(&pGC->tile.pixmap->drawable, SAA_ACCESS_W);
451    sscreen->fallback_count--;
452
453    if (pTile)
454	saa_fad_read(&pTile->drawable);
455 out_no_tile:
456    if (pGC->stipple)
457	saa_fad_read(&pGC->stipple->drawable);
458}
459
460static void
461saa_destroy_gc(GCPtr pGC)
462{
463    struct saa_gc_priv *sgc = saa_gc(pGC);
464
465    saa_swap(sgc, pGC, funcs);
466    (*pGC->funcs->DestroyGC) (pGC);
467    saa_swap(sgc, pGC, funcs);
468}
469
470static void
471saa_change_gc(GCPtr pGC, unsigned long mask)
472{
473    struct saa_gc_priv *sgc = saa_gc(pGC);
474
475    saa_swap(sgc, pGC, funcs);
476    (*pGC->funcs->ChangeGC) (pGC, mask);
477    saa_swap(sgc, pGC, funcs);
478}
479
480static void
481saa_copy_gc(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
482{
483    struct saa_gc_priv *sgc = saa_gc(pGCDst);
484
485    saa_swap(sgc, pGCDst, funcs);
486    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
487    saa_swap(sgc, pGCDst, funcs);
488}
489
490static void
491saa_change_clip(GCPtr pGC, int type, pointer pvalue, int nrects)
492{
493    struct saa_gc_priv *sgc = saa_gc(pGC);
494
495    saa_swap(sgc, pGC, funcs);
496    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
497    saa_swap(sgc, pGC, funcs);
498}
499
500static void
501saa_copy_clip(GCPtr pGCDst, GCPtr pGCSrc)
502{
503    struct saa_gc_priv *sgc = saa_gc(pGCDst);
504
505    saa_swap(sgc, pGCDst, funcs);
506    (*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
507    saa_swap(sgc, pGCDst, funcs);
508}
509
510static void
511saa_destroy_clip(GCPtr pGC)
512{
513    struct saa_gc_priv *sgc = saa_gc(pGC);
514
515    saa_swap(sgc, pGC, funcs);
516    (*pGC->funcs->DestroyClip) (pGC);
517    saa_swap(sgc, pGC, funcs);
518}
519
520static GCFuncs saa_gc_funcs = {
521    saa_validate_gc,
522    saa_change_gc,
523    saa_copy_gc,
524    saa_destroy_gc,
525    saa_change_clip,
526    saa_destroy_clip,
527    saa_copy_clip
528};
529
530/**
531 * saa_create_gc makes a new GC and hooks up its funcs handler, so that
532 * saa_validate_gc() will get called.
533 */
534int
535saa_create_gc(GCPtr pGC)
536{
537    ScreenPtr pScreen = pGC->pScreen;
538    struct saa_screen_priv *sscreen = saa_screen(pScreen);
539    struct saa_gc_priv *sgc = saa_gc(pGC);
540    Bool ret;
541
542    saa_swap(sscreen, pScreen, CreateGC);
543    ret = pScreen->CreateGC(pGC);
544    if (ret) {
545	saa_wrap(sgc, pGC, funcs, &saa_gc_funcs);
546	saa_wrap(sgc, pGC, ops, &saa_gc_ops);
547    }
548    saa_swap(sscreen, pScreen, CreateGC);
549
550    return ret;
551}
552
553static Bool
554saa_prepare_access_window(WindowPtr pWin)
555{
556    if (pWin->backgroundState == BackgroundPixmap) {
557	if (!saa_pad_read(&pWin->background.pixmap->drawable))
558	    return FALSE;
559    }
560
561    if (pWin->borderIsPixel == FALSE) {
562	if (!saa_pad_read(&pWin->border.pixmap->drawable)) {
563	    if (pWin->backgroundState == BackgroundPixmap)
564		saa_fad_read(&pWin->background.pixmap->drawable);
565	    return FALSE;
566	}
567    }
568    return TRUE;
569}
570
571static void
572saa_finish_access_window(WindowPtr pWin)
573{
574    if (pWin->backgroundState == BackgroundPixmap)
575	saa_fad_read(&pWin->background.pixmap->drawable);
576
577    if (pWin->borderIsPixel == FALSE)
578	saa_fad_read(&pWin->border.pixmap->drawable);
579}
580
581static Bool
582saa_change_window_attributes(WindowPtr pWin, unsigned long mask)
583{
584    Bool ret;
585
586    if (!saa_prepare_access_window(pWin))
587	return FALSE;
588    ret = fbChangeWindowAttributes(pWin, mask);
589    saa_finish_access_window(pWin);
590    return ret;
591}
592
593RegionPtr
594saa_bitmap_to_region(PixmapPtr pPix)
595{
596    RegionPtr ret;
597
598    if (!saa_pad_read(&pPix->drawable))
599	return NULL;
600    ret = fbPixmapToRegion(pPix);
601    saa_fad_read(&pPix->drawable);
602    return ret;
603}
604
605void
606saa_set_fallback_debug(ScreenPtr screen, Bool enable)
607{
608    struct saa_screen_priv *sscreen = saa_screen(screen);
609
610    sscreen->fallback_debug = enable;
611}
612
613/**
614 * saa_early_close_screen() Makes sure we call saa_destroy_pixmap on the
615 * miScreenInit() pixmap _before_ damageCloseScreen, after which it will
616 * generate an invalid memory access. Also unwraps the functions we
617 * wrapped _after_ DamageSetup().
618 */
619static Bool
620saa_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
621{
622    struct saa_screen_priv *sscreen = saa_screen(pScreen);
623
624    if (pScreen->devPrivate) {
625	/* Destroy the pixmap created by miScreenInit() *before*
626	 * chaining up as we finalize ourselves here and so this
627	 * is the last chance we have of releasing our resources
628	 * associated with the Pixmap. So do it first.
629	 */
630	(void)(*pScreen->DestroyPixmap) (pScreen->devPrivate);
631	pScreen->devPrivate = NULL;
632    }
633
634    saa_unwrap_early(sscreen, pScreen, CloseScreen);
635    saa_unwrap(sscreen, pScreen, DestroyPixmap);
636
637    return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
638}
639
640/**
641 * saa_close_screen() unwraps its wrapped screen functions and tears down SAA's
642 * screen private, before calling down to the next CloseScreen.
643 */
644Bool
645saa_close_screen(CLOSE_SCREEN_ARGS_DECL)
646{
647    struct saa_screen_priv *sscreen = saa_screen(pScreen);
648    struct saa_driver *driver = sscreen->driver;
649
650    saa_unwrap(sscreen, pScreen, CloseScreen);
651    saa_unwrap(sscreen, pScreen, CreateGC);
652    saa_unwrap(sscreen, pScreen, ChangeWindowAttributes);
653    saa_unwrap(sscreen, pScreen, CreatePixmap);
654    saa_unwrap(sscreen, pScreen, ModifyPixmapHeader);
655    saa_unwrap(sscreen, pScreen, BitmapToRegion);
656#ifdef RENDER
657    saa_render_takedown(pScreen);
658#endif
659    saa_unaccel_takedown(pScreen);
660    driver->takedown(driver);
661
662    free(sscreen);
663
664    return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
665}
666
667struct saa_driver *
668saa_get_driver(ScreenPtr pScreen)
669{
670    return saa_screen(pScreen)->driver;
671}
672
673/**
674 * @param pScreen screen being initialized
675 * @param pScreenInfo SAA driver record
676 *
677 * saa_driver_init sets up SAA given a driver record filled in by the driver.
678 * pScreenInfo should have been allocated by saa_driver_alloc().  See the
679 * comments in _SaaDriver for what must be filled in and what is optional.
680 *
681 * @return TRUE if SAA was successfully initialized.
682 */
683Bool
684saa_driver_init(ScreenPtr screen, struct saa_driver * saa_driver)
685{
686    struct saa_screen_priv *sscreen;
687
688    if (!saa_driver)
689	return FALSE;
690
691    if (saa_driver->saa_major != SAA_VERSION_MAJOR ||
692	saa_driver->saa_minor > SAA_VERSION_MINOR) {
693	LogMessage(X_ERROR,
694		   "SAA(%d): driver's SAA version requirements "
695		   "(%d.%d) are incompatible with SAA version (%d.%d)\n",
696		   screen->myNum, saa_driver->saa_major,
697		   saa_driver->saa_minor, SAA_VERSION_MAJOR, SAA_VERSION_MINOR);
698	return FALSE;
699    }
700#if 0
701    if (!saa_driver->prepare_solid) {
702	LogMessage(X_ERROR,
703		   "SAA(%d): saa_driver_t::prepare_solid must be "
704		   "non-NULL\n", screen->myNum);
705	return FALSE;
706    }
707
708    if (!saa_driver->prepare_copy) {
709	LogMessage(X_ERROR,
710		   "SAA(%d): saa_driver_t::prepare_copy must be "
711		   "non-NULL\n", screen->myNum);
712	return FALSE;
713    }
714#endif
715#ifdef SAA_DEVPRIVATEKEYREC
716    if (!dixRegisterPrivateKey(&saa_screen_index, PRIVATE_SCREEN, 0)) {
717	LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
718	return FALSE;
719    }
720    if (!dixRegisterPrivateKey(&saa_pixmap_index, PRIVATE_PIXMAP,
721			       saa_driver->pixmap_size)) {
722	LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
723	return FALSE;
724    }
725    if (!dixRegisterPrivateKey(&saa_gc_index, PRIVATE_GC,
726			       sizeof(struct saa_gc_priv))) {
727	LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
728	return FALSE;
729    }
730#else
731    if (!dixRequestPrivate(&saa_screen_index, 0)) {
732	LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
733	return FALSE;
734    }
735    if (!dixRequestPrivate(&saa_pixmap_index, saa_driver->pixmap_size)) {
736	LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
737	return FALSE;
738    }
739    if (!dixRequestPrivate(&saa_gc_index, sizeof(struct saa_gc_priv))) {
740	LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
741	return FALSE;
742    }
743#endif
744
745    sscreen = calloc(1, sizeof(*sscreen));
746
747    if (!sscreen) {
748	LogMessage(X_WARNING,
749		   "SAA(%d): Failed to allocate screen private\n",
750		   screen->myNum);
751	return FALSE;
752    }
753
754    sscreen->driver = saa_driver;
755    dixSetPrivate(&screen->devPrivates, &saa_screen_index, sscreen);
756
757    /*
758     * Replace various fb screen functions
759     */
760
761    saa_wrap(sscreen, screen, CloseScreen, saa_close_screen);
762    saa_wrap(sscreen, screen, CreateGC, saa_create_gc);
763    saa_wrap(sscreen, screen, ChangeWindowAttributes,
764	     saa_change_window_attributes);
765    saa_wrap(sscreen, screen, CreatePixmap, saa_create_pixmap);
766    saa_wrap(sscreen, screen, ModifyPixmapHeader, saa_modify_pixmap_header);
767    saa_wrap(sscreen, screen, BitmapToRegion, saa_bitmap_to_region);
768    saa_unaccel_setup(screen);
769#ifdef RENDER
770    saa_render_setup(screen);
771#endif
772
773    /*
774     * Correct saa functionality relies on Damage, so set it up now.
775     * Note that this must happen _after_ wrapping the rendering functionality
776     * so that damage happens outside of saa.
777     */
778    if (!DamageSetup(screen))
779	return FALSE;
780
781    /*
782     * Wrap DestroyPixmap after DamageSetup, so that saa_destroy_pixmap is
783     * called _before_ damageDestroyPixmap. This is to make damageDestroyPixmap
784     * doesn't free objects pointed to by our damage pointers.
785     *
786     * Also wrap an early CloseScreen to perform actions needed to be done
787     * before damageCloseScreen and to unwrap DestroyPixmap correctly.
788     */
789    saa_wrap(sscreen, screen, DestroyPixmap, saa_destroy_pixmap);
790    saa_wrap_early(sscreen, screen, CloseScreen, saa_early_close_screen);
791
792    return TRUE;
793}
794
795Bool
796saa_resources_init(ScreenPtr screen)
797{
798/*    if (!saa_glyphs_init(screen))
799	return FALSE;
800*/
801    return TRUE;
802}
803