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 UXA, 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 "uxa-priv.h"
38#include <X11/fonts/fontstruct.h>
39#include "dixfontstr.h"
40#include "uxa.h"
41
42DevPrivateKeyRec uxa_screen_index;
43
44/**
45 * uxa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
46 *
47 * @param pDrawable the drawable being requested.
48 *
49 * This function returns the backing pixmap for a drawable, whether it is a
50 * redirected window, unredirected window, or already a pixmap.  Note that
51 * coordinate translation is needed when drawing to the backing pixmap of a
52 * redirected window, and the translation coordinates are provided by calling
53 * uxa_get_drawable_pixmap() on the drawable.
54 */
55PixmapPtr
56uxa_get_drawable_pixmap(DrawablePtr pDrawable)
57{
58     if (pDrawable->type == DRAWABLE_WINDOW)
59	return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
60     else
61	return (PixmapPtr) pDrawable;
62}
63
64/**
65 * Sets the offsets to add to coordinates to make them address the same bits in
66 * the backing drawable. These coordinates are nonzero only for redirected
67 * windows.
68 */
69void
70uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
71			 int *xp, int *yp)
72{
73#ifdef COMPOSITE
74    if (pDrawable->type == DRAWABLE_WINDOW) {
75	*xp = -pPixmap->screen_x;
76	*yp = -pPixmap->screen_y;
77	return;
78    }
79#endif
80
81    *xp = 0;
82    *yp = 0;
83}
84
85/**
86 * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen
87 * memory, meaning that acceleration could probably be done to it, and that it
88 * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
89 * with the CPU.
90 *
91 * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
92 * deal with moving pixmaps in and out of system memory), UXA will give drivers
93 * pixmaps as arguments for which uxa_pixmap_is_offscreen() is TRUE.
94 *
95 * @return TRUE if the given drawable is in framebuffer memory.
96 */
97Bool
98uxa_pixmap_is_offscreen(PixmapPtr p)
99{
100    ScreenPtr	    pScreen = p->drawable.pScreen;
101    uxa_screen_t    *uxa_screen = uxa_get_screen(pScreen);
102
103    if (uxa_screen->info->pixmap_is_offscreen)
104	return uxa_screen->info->pixmap_is_offscreen(p);
105
106    return FALSE;
107}
108
109/**
110 * uxa_drawable_is_offscreen() is a convenience wrapper for uxa_pixmap_is_offscreen().
111 */
112Bool
113uxa_drawable_is_offscreen (DrawablePtr pDrawable)
114{
115    return uxa_pixmap_is_offscreen (uxa_get_drawable_pixmap (pDrawable));
116}
117
118/**
119  * Returns the pixmap which backs a drawable, and the offsets to add to
120  * coordinates to make them address the same bits in the backing drawable.
121  */
122PixmapPtr
123uxa_get_offscreen_pixmap (DrawablePtr drawable, int *xp, int *yp)
124{
125    PixmapPtr   pixmap = uxa_get_drawable_pixmap (drawable);
126
127    uxa_get_drawable_deltas (drawable, pixmap, xp, yp);
128
129    if (uxa_pixmap_is_offscreen (pixmap))
130	return pixmap;
131    else
132	return NULL;
133}
134
135
136
137/**
138 * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler.
139 *
140 * It deals with waiting for synchronization with the card, determining if
141 * PrepareAccess() is necessary, and working around PrepareAccess() failure.
142 */
143Bool
144uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access)
145{
146    ScreenPtr	    pScreen = pDrawable->pScreen;
147    uxa_screen_t    *uxa_screen = uxa_get_screen(pScreen);
148    PixmapPtr	    pPixmap = uxa_get_drawable_pixmap (pDrawable);
149    Bool	    offscreen = uxa_pixmap_is_offscreen(pPixmap);
150
151    if (!offscreen)
152	return TRUE;
153
154    if (uxa_screen->info->prepare_access)
155	return (*uxa_screen->info->prepare_access) (pPixmap, access);
156    return TRUE;
157}
158
159/**
160 * uxa_finish_access() is UXA's wrapper for the driver's finish_access() handler.
161 *
162 * It deals with calling the driver's finish_access() only if necessary.
163 */
164void
165uxa_finish_access(DrawablePtr pDrawable)
166{
167    ScreenPtr	    pScreen = pDrawable->pScreen;
168    uxa_screen_t    *uxa_screen = uxa_get_screen(pScreen);
169    PixmapPtr	    pPixmap = uxa_get_drawable_pixmap (pDrawable);
170
171    if (uxa_screen->info->finish_access == NULL)
172	return;
173
174    if (!uxa_pixmap_is_offscreen (pPixmap))
175	return;
176
177    (*uxa_screen->info->finish_access) (pPixmap);
178}
179
180/**
181 * uxa_validate_gc() sets the ops to UXA's implementations, which may be
182 * accelerated or may sync the card and fall back to fb.
183 */
184static void
185uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
186{
187    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
188     * Preempt fbValidateGC by doing its work and masking the change out, so
189     * that we can do the Prepare/finish_access.
190     */
191#ifdef FB_24_32BIT
192    if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
193	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
194	fbGetRotatedPixmap(pGC) = 0;
195    }
196
197    if (pGC->fillStyle == FillTiled) {
198	PixmapPtr	pOldTile, pNewTile;
199
200	pOldTile = pGC->tile.pixmap;
201	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
202	{
203	    pNewTile = fbGetRotatedPixmap(pGC);
204	    if (!pNewTile ||
205		pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
206	    {
207		if (pNewTile)
208		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
209		/* fb24_32ReformatTile will do direct access of a newly-
210		 * allocated pixmap.  This isn't a problem yet, since we don't
211		 * put pixmaps in FB until at least one accelerated UXA op.
212		 */
213		if (uxa_prepare_access(&pOldTile->drawable, UXA_ACCESS_RO)) {
214		    pNewTile = fb24_32ReformatTile (pOldTile,
215						    pDrawable->bitsPerPixel);
216		    uxa_finish_access(&pOldTile->drawable);
217		}
218	    }
219	    if (pNewTile)
220	    {
221		fbGetRotatedPixmap(pGC) = pOldTile;
222		pGC->tile.pixmap = pNewTile;
223		changes |= GCTile;
224	    }
225	}
226    }
227#endif
228    if (changes & GCTile) {
229	if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
230					     pDrawable->bitsPerPixel))
231	{
232	    if (uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RW)) {
233		fbPadPixmap (pGC->tile.pixmap);
234		uxa_finish_access(&pGC->tile.pixmap->drawable);
235	    }
236	}
237	/* Mask out the GCTile change notification, now that we've done FB's
238	 * job for it.
239	 */
240	changes &= ~GCTile;
241    }
242
243    if (changes & GCStipple && pGC->stipple) {
244	/* We can't inline stipple handling like we do for GCTile because it sets
245	 * fbgc privates.
246	 */
247	if (uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RW)) {
248	    fbValidateGC (pGC, changes, pDrawable);
249	    uxa_finish_access(&pGC->stipple->drawable);
250	}
251    } else {
252	fbValidateGC (pGC, changes, pDrawable);
253    }
254
255    pGC->ops = (GCOps *) &uxa_ops;
256}
257
258static GCFuncs	uxaGCFuncs = {
259    uxa_validate_gc,
260    miChangeGC,
261    miCopyGC,
262    miDestroyGC,
263    miChangeClip,
264    miDestroyClip,
265    miCopyClip
266};
267
268/**
269 * uxa_create_gc makes a new GC and hooks up its funcs handler, so that
270 * uxa_validate_gc() will get called.
271 */
272static int
273uxa_create_gc (GCPtr pGC)
274{
275    if (!fbCreateGC (pGC))
276	return FALSE;
277
278    pGC->funcs = &uxaGCFuncs;
279
280    return TRUE;
281}
282
283Bool
284uxa_prepare_access_window(WindowPtr pWin)
285{
286    if (pWin->backgroundState == BackgroundPixmap) {
287        if (!uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_ACCESS_RO))
288	    return FALSE;
289    }
290
291    if (pWin->borderIsPixel == FALSE) {
292        if (!uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_ACCESS_RO)) {
293	    if (pWin->backgroundState == BackgroundPixmap)
294		uxa_finish_access(&pWin->background.pixmap->drawable);
295	    return FALSE;
296	}
297    }
298    return TRUE;
299}
300
301void
302uxa_finish_access_window(WindowPtr pWin)
303{
304    if (pWin->backgroundState == BackgroundPixmap)
305        uxa_finish_access(&pWin->background.pixmap->drawable);
306
307    if (pWin->borderIsPixel == FALSE)
308        uxa_finish_access(&pWin->border.pixmap->drawable);
309}
310
311static Bool
312uxa_change_window_attributes(WindowPtr pWin, unsigned long mask)
313{
314    Bool ret;
315
316    if (!uxa_prepare_access_window(pWin))
317	return FALSE;
318    ret = fbChangeWindowAttributes(pWin, mask);
319    uxa_finish_access_window(pWin);
320    return ret;
321}
322
323static RegionPtr
324uxa_bitmap_to_region(PixmapPtr pPix)
325{
326  RegionPtr ret;
327  if (!uxa_prepare_access(&pPix->drawable, UXA_ACCESS_RO))
328    return NULL;
329  ret = fbPixmapToRegion(pPix);
330  uxa_finish_access(&pPix->drawable);
331  return ret;
332}
333
334static void
335uxa_xorg_enable_disable_fb_access (int index, Bool enable)
336{
337    ScreenPtr screen = screenInfo.screens[index];
338    uxa_screen_t *uxa_screen = uxa_get_screen(screen);
339
340    if (!enable && uxa_screen->disableFbCount++ == 0)
341	uxa_screen->swappedOut = TRUE;
342
343    if (enable && --uxa_screen->disableFbCount == 0)
344	uxa_screen->swappedOut = FALSE;
345
346    if (uxa_screen->SavedEnableDisableFBAccess)
347       uxa_screen->SavedEnableDisableFBAccess(index, enable);
348}
349
350void
351uxa_set_fallback_debug (ScreenPtr screen, Bool enable)
352{
353    uxa_screen_t *uxa_screen = uxa_get_screen(screen);
354
355    uxa_screen->fallback_debug = enable;
356}
357
358/**
359 * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's
360 * screen private, before calling down to the next CloseSccreen.
361 */
362static Bool
363uxa_close_screen(int i, ScreenPtr pScreen)
364{
365    uxa_screen_t	*uxa_screen = uxa_get_screen(pScreen);
366    ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
367#ifdef RENDER
368    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
369#endif
370
371    uxa_glyphs_fini(pScreen);
372
373    pScreen->CreateGC = uxa_screen->SavedCreateGC;
374    pScreen->CloseScreen = uxa_screen->SavedCloseScreen;
375    pScreen->GetImage = uxa_screen->SavedGetImage;
376    pScreen->GetSpans = uxa_screen->SavedGetSpans;
377    pScreen->CreatePixmap = uxa_screen->SavedCreatePixmap;
378    pScreen->DestroyPixmap = uxa_screen->SavedDestroyPixmap;
379    pScreen->CopyWindow = uxa_screen->SavedCopyWindow;
380    pScreen->ChangeWindowAttributes = uxa_screen->SavedChangeWindowAttributes;
381    pScreen->BitmapToRegion = uxa_screen->SavedBitmapToRegion;
382    scrn->EnableDisableFBAccess = uxa_screen->SavedEnableDisableFBAccess;
383#ifdef RENDER
384    if (ps) {
385	ps->Composite = uxa_screen->SavedComposite;
386	ps->Glyphs = uxa_screen->SavedGlyphs;
387	ps->Trapezoids = uxa_screen->SavedTrapezoids;
388	ps->AddTraps = uxa_screen->SavedAddTraps;
389	ps->Triangles = uxa_screen->SavedTriangles;
390    }
391#endif
392
393    xfree (uxa_screen);
394
395    return (*pScreen->CloseScreen) (i, pScreen);
396}
397
398/**
399 * This function allocates a driver structure for UXA drivers to fill in.  By
400 * having UXA allocate the structure, the driver structure can be extended
401 * without breaking ABI between UXA and the drivers.  The driver's
402 * responsibility is to check beforehand that the UXA module has a matching
403 * major number and sufficient minor.  Drivers are responsible for freeing the
404 * driver structure using xfree().
405 *
406 * @return a newly allocated, zero-filled driver structure
407 */
408uxa_driver_t *
409uxa_driver_alloc(void)
410{
411    return xcalloc(1, sizeof(uxa_driver_t));
412}
413
414/**
415 * @param pScreen screen being initialized
416 * @param pScreenInfo UXA driver record
417 *
418 * uxa_driver_init sets up UXA given a driver record filled in by the driver.
419 * pScreenInfo should have been allocated by uxa_driver_alloc().  See the
420 * comments in _UxaDriver for what must be filled in and what is optional.
421 *
422 * @return TRUE if UXA was successfully initialized.
423 */
424Bool
425uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver)
426{
427    uxa_screen_t	*uxa_screen;
428    ScrnInfoPtr scrn = xf86Screens[screen->myNum];
429#ifdef RENDER
430    PictureScreenPtr	ps;
431#endif
432
433    if (!uxa_driver)
434	return FALSE;
435
436    if (uxa_driver->uxa_major != UXA_VERSION_MAJOR ||
437	uxa_driver->uxa_minor > UXA_VERSION_MINOR)
438    {
439	LogMessage(X_ERROR, "UXA(%d): driver's UXA version requirements "
440		   "(%d.%d) are incompatible with UXA version (%d.%d)\n",
441		   screen->myNum,
442		   uxa_driver->uxa_major, uxa_driver->uxa_minor,
443		   UXA_VERSION_MAJOR, UXA_VERSION_MINOR);
444	return FALSE;
445    }
446
447    if (!uxa_driver->prepare_solid) {
448	LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_solid must be "
449		   "non-NULL\n", screen->myNum);
450	return FALSE;
451    }
452
453    if (!uxa_driver->prepare_copy) {
454	LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_copy must be "
455		   "non-NULL\n", screen->myNum);
456	return FALSE;
457    }
458
459#ifdef RENDER
460    ps = GetPictureScreenIfSet(screen);
461#endif
462
463#if HAS_DIXREGISTERPRIVATEKEY
464    if (!dixRegisterPrivateKey(&uxa_screen_index, PRIVATE_SCREEN, 0))
465	return FALSE;
466#endif
467    uxa_screen = xcalloc (sizeof (uxa_screen_t), 1);
468
469    if (!uxa_screen) {
470        LogMessage(X_WARNING, "UXA(%d): Failed to allocate screen private\n",
471		   screen->myNum);
472	return FALSE;
473    }
474
475    uxa_screen->info = uxa_driver;
476
477    dixSetPrivate(&screen->devPrivates, &uxa_screen_index, uxa_screen);
478
479//    exaDDXDriverInit(screen);
480
481    /*
482     * Replace various fb screen functions
483     */
484    uxa_screen->SavedCloseScreen = screen->CloseScreen;
485    screen->CloseScreen = uxa_close_screen;
486
487    uxa_screen->SavedCreateGC = screen->CreateGC;
488    screen->CreateGC = uxa_create_gc;
489
490    uxa_screen->SavedGetImage = screen->GetImage;
491    screen->GetImage = uxa_get_image;
492
493    uxa_screen->SavedGetSpans = screen->GetSpans;
494    screen->GetSpans = uxa_check_get_spans;
495
496    uxa_screen->SavedCopyWindow = screen->CopyWindow;
497    screen->CopyWindow = uxa_copy_window;
498
499    uxa_screen->SavedChangeWindowAttributes = screen->ChangeWindowAttributes;
500    screen->ChangeWindowAttributes = uxa_change_window_attributes;
501
502    uxa_screen->SavedBitmapToRegion = screen->BitmapToRegion;
503    screen->BitmapToRegion = uxa_bitmap_to_region;
504
505    uxa_screen->SavedEnableDisableFBAccess = scrn->EnableDisableFBAccess;
506    scrn->EnableDisableFBAccess = uxa_xorg_enable_disable_fb_access;
507
508#ifdef RENDER
509    if (ps) {
510        uxa_screen->SavedComposite = ps->Composite;
511	ps->Composite = uxa_composite;
512
513	uxa_screen->SavedGlyphs = ps->Glyphs;
514	ps->Glyphs = uxa_glyphs;
515
516	uxa_screen->SavedTriangles = ps->Triangles;
517	ps->Triangles = uxa_triangles;
518
519	uxa_screen->SavedTrapezoids = ps->Trapezoids;
520	ps->Trapezoids = uxa_trapezoids;
521
522	uxa_screen->SavedAddTraps = ps->AddTraps;
523	ps->AddTraps = uxa_check_add_traps;
524    }
525#endif
526
527#ifdef MITSHM
528    /* Re-register with the MI funcs, which don't allow shared pixmaps.
529     * Shared pixmaps are almost always a performance loss for us, but this
530     * still allows for SHM PutImage.
531     */
532    ShmRegisterFuncs(screen, &uxa_shm_funcs);
533#endif
534
535    uxa_glyphs_init(screen);
536
537    LogMessage(X_INFO, "UXA(%d): Driver registered support for the following"
538	       " operations:\n", screen->myNum);
539    assert(uxa_driver->prepare_solid != NULL);
540    LogMessage(X_INFO, "        solid\n");
541    assert(uxa_driver->prepare_copy != NULL);
542    LogMessage(X_INFO, "        copy\n");
543    if (uxa_driver->prepare_composite != NULL) {
544	LogMessage(X_INFO, "        composite (RENDER acceleration)\n");
545    }
546    if (uxa_driver->put_image != NULL) {
547	LogMessage(X_INFO, "        put_image\n");
548    }
549    if (uxa_driver->get_image != NULL) {
550	LogMessage(X_INFO, "        get_image\n");
551    }
552
553    return TRUE;
554}
555
556/**
557 * uxa_driver_fini tears down UXA on a given screen.
558 *
559 * @param pScreen screen being torn down.
560 */
561void
562uxa_driver_fini (ScreenPtr pScreen)
563{
564    /*right now does nothing*/
565}
566