1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4Copyright 2000 VA Linux Systems, Inc.
5Copyright (c) 2002, 2009 Apple Computer, Inc.
6All Rights Reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sub license, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice (including the
17next paragraph) shall be included in all copies or substantial portions
18of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28**************************************************************************/
29
30/*
31 * Authors:
32 *   Jens Owen <jens@valinux.com>
33 *   Rickard E. (Rik) Faith <faith@valinux.com>
34 *
35 */
36
37#ifdef HAVE_DIX_CONFIG_H
38#include <dix-config.h>
39#endif
40
41#ifdef XFree86LOADER
42#include "xf86.h"
43#include "xf86_ansic.h"
44#else
45#include <sys/time.h>
46#include <unistd.h>
47#endif
48
49#include <X11/X.h>
50#include <X11/Xproto.h>
51#include <fcntl.h>
52#include <sys/mman.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55#include "misc.h"
56#include "dixstruct.h"
57#include "extnsionst.h"
58#include "colormapst.h"
59#include "cursorstr.h"
60#include "scrnintstr.h"
61#include "windowstr.h"
62#include "servermd.h"
63#define _APPLEDRI_SERVER_
64#include "appledristr.h"
65#include "swaprep.h"
66#include "dri.h"
67#include "dristruct.h"
68#include "mi.h"
69#include "mipointer.h"
70#include "rootless.h"
71#include "x-hash.h"
72#include "x-hook.h"
73#include "driWrap.h"
74
75#include <AvailabilityMacros.h>
76
77static DevPrivateKeyRec DRIScreenPrivKeyRec;
78#define DRIScreenPrivKey (&DRIScreenPrivKeyRec)
79static DevPrivateKeyRec DRIWindowPrivKeyRec;
80#define DRIWindowPrivKey (&DRIWindowPrivKeyRec)
81static DevPrivateKeyRec DRIPixmapPrivKeyRec;
82#define DRIPixmapPrivKey (&DRIPixmapPrivKeyRec)
83static DevPrivateKeyRec DRIPixmapBufferPrivKeyRec;
84#define DRIPixmapBufferPrivKey (&DRIPixmapBufferPrivKeyRec)
85
86static RESTYPE DRIDrawablePrivResType;
87
88static x_hash_table *surface_hash;      /* maps surface ids -> drawablePrivs */
89
90static Bool DRIFreePixmapImp(DrawablePtr pDrawable);
91
92typedef struct {
93    DrawablePtr pDrawable;
94    int refCount;
95    int bytesPerPixel;
96    int width;
97    int height;
98    char shmPath[PATH_MAX];
99    int fd; /* From shm_open (for now) */
100    size_t length; /* length of buffer */
101    void *buffer;
102} DRIPixmapBuffer, *DRIPixmapBufferPtr;
103
104Bool
105DRIScreenInit(ScreenPtr pScreen)
106{
107    DRIScreenPrivPtr    pDRIPriv;
108    int                 i;
109
110    if (!dixRegisterPrivateKey(&DRIScreenPrivKeyRec, PRIVATE_SCREEN, 0))
111	return FALSE;
112    if (!dixRegisterPrivateKey(&DRIWindowPrivKeyRec, PRIVATE_WINDOW, 0))
113	return FALSE;
114    if (!dixRegisterPrivateKey(&DRIPixmapPrivKeyRec, PRIVATE_PIXMAP, 0))
115	return FALSE;
116    if (!dixRegisterPrivateKey(&DRIPixmapBufferPrivKeyRec, PRIVATE_PIXMAP, 0))
117	return FALSE;
118
119    pDRIPriv = (DRIScreenPrivPtr) calloc(1, sizeof(DRIScreenPrivRec));
120    if (!pDRIPriv) {
121	dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
122        return FALSE;
123    }
124
125    dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, pDRIPriv);
126    pDRIPriv->directRenderingSupport = TRUE;
127    pDRIPriv->nrWindows = 0;
128
129    /* Initialize drawable tables */
130    for (i = 0; i < DRI_MAX_DRAWABLES; i++) {
131        pDRIPriv->DRIDrawables[i] = NULL;
132    }
133
134    return TRUE;
135}
136
137Bool
138DRIFinishScreenInit(ScreenPtr pScreen)
139{
140    DRIScreenPrivPtr  pDRIPriv = DRI_SCREEN_PRIV(pScreen);
141
142    /* Wrap DRI support */
143    pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
144    pScreen->ValidateTree = DRIValidateTree;
145
146    pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
147    pScreen->PostValidateTree = DRIPostValidateTree;
148
149    pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
150    pScreen->WindowExposures = DRIWindowExposures;
151
152    pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
153    pScreen->CopyWindow = DRICopyWindow;
154
155    pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
156    pScreen->ClipNotify = DRIClipNotify;
157
158    //    ErrorF("[DRI] screen %d installation complete\n", pScreen->myNum);
159
160    return DRIWrapInit(pScreen);
161}
162
163void
164DRICloseScreen(ScreenPtr pScreen)
165{
166    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
167
168    if (pDRIPriv && pDRIPriv->directRenderingSupport) {
169        free(pDRIPriv);
170	dixSetPrivate(&pScreen->devPrivates, DRIScreenPrivKey, NULL);
171    }
172}
173
174Bool
175DRIExtensionInit(void)
176{
177    DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete,
178						   "DRIDrawable");
179
180    return DRIDrawablePrivResType != 0;
181}
182
183void
184DRIReset(void)
185{
186    /*
187     * This stub routine is called when the X Server recycles, resources
188     * allocated by DRIExtensionInit need to be managed here.
189     *
190     * Currently this routine is a stub because all the interesting resources
191     * are managed via the screen init process.
192     */
193}
194
195Bool
196DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable)
197{
198    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
199
200    if (pDRIPriv)
201        *isCapable = pDRIPriv->directRenderingSupport;
202    else
203        *isCapable = FALSE;
204
205    return TRUE;
206}
207
208Bool
209DRIAuthConnection(ScreenPtr pScreen, unsigned int magic)
210{
211#if 0
212    /* FIXME: something? */
213
214    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
215
216    if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE;
217#endif
218    return TRUE;
219}
220
221static void
222DRIUpdateSurface(DRIDrawablePrivPtr pDRIDrawablePriv, DrawablePtr pDraw)
223{
224    xp_window_changes wc;
225    unsigned int flags = 0;
226
227    if (pDRIDrawablePriv->sid == 0)
228        return;
229
230#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
231    wc.depth = (pDraw->bitsPerPixel == 32 ? XP_DEPTH_ARGB8888
232                : pDraw->bitsPerPixel == 16 ? XP_DEPTH_RGB555 : XP_DEPTH_NIL);
233    if (wc.depth != XP_DEPTH_NIL)
234        flags |= XP_DEPTH;
235#endif
236
237    if (pDraw->type == DRAWABLE_WINDOW) {
238        WindowPtr pWin = (WindowPtr) pDraw;
239        WindowPtr pTopWin = TopLevelParent(pWin);
240
241        wc.x = pWin->drawable.x - (pTopWin->drawable.x - pTopWin->borderWidth);
242        wc.y = pWin->drawable.y - (pTopWin->drawable.y - pTopWin->borderWidth);
243        wc.width = pWin->drawable.width + 2 * pWin->borderWidth;
244        wc.height = pWin->drawable.height + 2 * pWin->borderWidth;
245        wc.bit_gravity = XP_GRAVITY_NONE;
246
247        wc.shape_nrects = RegionNumRects(&pWin->clipList);
248        wc.shape_rects = RegionRects(&pWin->clipList);
249        wc.shape_tx = - (pTopWin->drawable.x - pTopWin->borderWidth);
250        wc.shape_ty = - (pTopWin->drawable.y - pTopWin->borderWidth);
251
252        flags |= XP_BOUNDS | XP_SHAPE;
253
254    } else if (pDraw->type == DRAWABLE_PIXMAP) {
255        wc.x = 0;
256        wc.y = 0;
257        wc.width = pDraw->width;
258        wc.height = pDraw->height;
259        wc.bit_gravity = XP_GRAVITY_NONE;
260        flags |= XP_BOUNDS;
261    }
262
263    xp_configure_surface(pDRIDrawablePriv->sid, flags, &wc);
264}
265
266/* Return NULL if an error occurs. */
267static DRIDrawablePrivPtr
268CreateSurfaceForWindow(ScreenPtr pScreen, WindowPtr pWin, xp_window_id *widPtr) {
269    DRIDrawablePrivPtr pDRIDrawablePriv;
270    xp_window_id wid = 0;
271
272    *widPtr = 0;
273
274    pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
275
276    if (pDRIDrawablePriv == NULL) {
277	xp_error err;
278	xp_window_changes wc;
279
280	/* allocate a DRI Window Private record */
281	if (!(pDRIDrawablePriv = malloc(sizeof(*pDRIDrawablePriv)))) {
282	    return NULL;
283	}
284
285	pDRIDrawablePriv->pDraw = (DrawablePtr)pWin;
286	pDRIDrawablePriv->pScreen = pScreen;
287	pDRIDrawablePriv->refCount = 0;
288	pDRIDrawablePriv->drawableIndex = -1;
289	pDRIDrawablePriv->notifiers = NULL;
290
291	/* find the physical window */
292	wid = x_cvt_vptr_to_uint(RootlessFrameForWindow(pWin, TRUE));
293
294	if (wid == 0) {
295	    free(pDRIDrawablePriv);
296	    return NULL;
297	}
298
299	/* allocate the physical surface */
300	err = xp_create_surface(wid, &pDRIDrawablePriv->sid);
301
302	if (err != Success) {
303	    free(pDRIDrawablePriv);
304	    return NULL;
305	}
306
307	/* Make it visible */
308	wc.stack_mode = XP_MAPPED_ABOVE;
309	wc.sibling = 0;
310	err = xp_configure_surface(pDRIDrawablePriv->sid, XP_STACKING, &wc);
311
312	if (err != Success) {
313	    xp_destroy_surface(pDRIDrawablePriv->sid);
314	    free(pDRIDrawablePriv);
315	    return NULL;
316	}
317
318	/* save private off of preallocated index */
319	dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey,
320		      pDRIDrawablePriv);
321    }
322
323    *widPtr = wid;
324
325    return pDRIDrawablePriv;
326}
327
328/* Return NULL if an error occurs. */
329static DRIDrawablePrivPtr
330CreateSurfaceForPixmap(ScreenPtr pScreen, PixmapPtr pPix) {
331    DRIDrawablePrivPtr pDRIDrawablePriv;
332
333    pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix);
334
335    if (pDRIDrawablePriv == NULL) {
336	xp_error err;
337
338	/* allocate a DRI Window Private record */
339	if (!(pDRIDrawablePriv = calloc(1, sizeof(*pDRIDrawablePriv)))) {
340	    return NULL;
341	}
342
343	pDRIDrawablePriv->pDraw = (DrawablePtr)pPix;
344	pDRIDrawablePriv->pScreen = pScreen;
345	pDRIDrawablePriv->refCount = 0;
346	pDRIDrawablePriv->drawableIndex = -1;
347	pDRIDrawablePriv->notifiers = NULL;
348
349	/* Passing a null window id to Xplugin in 10.3+ asks for
350	   an accelerated offscreen surface. */
351
352	err = xp_create_surface(0, &pDRIDrawablePriv->sid);
353	if (err != Success) {
354	    free(pDRIDrawablePriv);
355	    return NULL;
356	}
357
358	/*
359	 * The DRIUpdateSurface will be called to resize the surface
360	 * after this function, if the export is successful.
361	 */
362
363	/* save private off of preallocated index */
364	dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey,
365		      pDRIDrawablePriv);
366    }
367
368    return pDRIDrawablePriv;
369}
370
371
372Bool
373DRICreateSurface(ScreenPtr pScreen, Drawable id,
374                 DrawablePtr pDrawable, xp_client_id client_id,
375                 xp_surface_id *surface_id, unsigned int ret_key[2],
376                 void (*notify) (void *arg, void *data), void *notify_data)
377{
378    DRIScreenPrivPtr    pDRIPriv = DRI_SCREEN_PRIV(pScreen);
379    xp_window_id        wid = 0;
380    DRIDrawablePrivPtr  pDRIDrawablePriv;
381
382    if (pDrawable->type == DRAWABLE_WINDOW) {
383	pDRIDrawablePriv = CreateSurfaceForWindow(pScreen,
384						  (WindowPtr)pDrawable, &wid);
385
386	if(NULL == pDRIDrawablePriv)
387	    return FALSE; /*error*/
388    }
389#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
390    else if (pDrawable->type == DRAWABLE_PIXMAP) {
391	pDRIDrawablePriv = CreateSurfaceForPixmap(pScreen,
392						  (PixmapPtr)pDrawable);
393
394	if(NULL == pDRIDrawablePriv)
395	    return FALSE; /*error*/
396    }
397#endif
398    else {
399	/* We handle GLXPbuffers in a different way (via CGL). */
400        return FALSE;
401    }
402
403
404    /* Finish initialization of new surfaces */
405    if (pDRIDrawablePriv->refCount == 0) {
406        unsigned int key[2] = {0};
407        xp_error err;
408
409        /* try to give the client access to the surface */
410        if (client_id != 0) {
411	    /*
412	     * Xplugin accepts a 0 wid if the surface id is offscreen, such
413	     * as for a pixmap.
414	     */
415            err = xp_export_surface(wid, pDRIDrawablePriv->sid,
416                                    client_id, key);
417            if (err != Success) {
418                xp_destroy_surface(pDRIDrawablePriv->sid);
419                free(pDRIDrawablePriv);
420
421		/*
422		 * Now set the dix privates to NULL that were previously set.
423		 * This prevents reusing an invalid pointer.
424		 */
425		if(pDrawable->type == DRAWABLE_WINDOW) {
426		    WindowPtr pWin = (WindowPtr)pDrawable;
427
428		    dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL);
429		} else if(pDrawable->type == DRAWABLE_PIXMAP) {
430		    PixmapPtr pPix = (PixmapPtr)pDrawable;
431
432		    dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL);
433		}
434
435                return FALSE;
436            }
437        }
438
439        pDRIDrawablePriv->key[0] = key[0];
440        pDRIDrawablePriv->key[1] = key[1];
441
442        ++pDRIPriv->nrWindows;
443
444        /* and stash it by surface id */
445        if (surface_hash == NULL)
446            surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
447        x_hash_table_insert(surface_hash,
448                            x_cvt_uint_to_vptr(pDRIDrawablePriv->sid), pDRIDrawablePriv);
449
450        /* track this in case this window is destroyed */
451        AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable);
452
453        /* Initialize shape */
454        DRIUpdateSurface(pDRIDrawablePriv, pDrawable);
455    }
456
457    pDRIDrawablePriv->refCount++;
458
459    *surface_id = pDRIDrawablePriv->sid;
460
461    if (ret_key != NULL) {
462        ret_key[0] = pDRIDrawablePriv->key[0];
463        ret_key[1] = pDRIDrawablePriv->key[1];
464    }
465
466    if (notify != NULL) {
467        pDRIDrawablePriv->notifiers = x_hook_add(pDRIDrawablePriv->notifiers,
468                                                 notify, notify_data);
469    }
470
471    return TRUE;
472}
473
474Bool
475DRIDestroySurface(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable,
476                  void (*notify) (void *, void *), void *notify_data)
477{
478    DRIDrawablePrivPtr  pDRIDrawablePriv;
479
480    if (pDrawable->type == DRAWABLE_WINDOW) {
481        pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW((WindowPtr)pDrawable);
482    } else if (pDrawable->type == DRAWABLE_PIXMAP) {
483        pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP((PixmapPtr)pDrawable);
484    } else {
485        return FALSE;
486    }
487
488    if (pDRIDrawablePriv != NULL) {
489	/*
490	 * This doesn't seem to be used, because notify is NULL in all callers.
491	 */
492
493        if (notify != NULL) {
494            pDRIDrawablePriv->notifiers = x_hook_remove(pDRIDrawablePriv->notifiers,
495                                                        notify, notify_data);
496        }
497
498	--pDRIDrawablePriv->refCount;
499
500	/*
501	 * Check if the drawable privates still have a reference to the
502	 * surface.
503	 */
504
505        if (pDRIDrawablePriv->refCount <= 0) {
506            /*
507	     * This calls back to DRIDrawablePrivDelete which
508	     * frees the private area and dispatches events, if needed.
509	     */
510            FreeResourceByType(id, DRIDrawablePrivResType, FALSE);
511        }
512    }
513
514    return TRUE;
515}
516
517/*
518 * The assumption is that this is called when the refCount of a surface
519 * drops to <= 0, or the window/pixmap is destroyed.
520 */
521Bool
522DRIDrawablePrivDelete(pointer pResource, XID id)
523{
524    DrawablePtr         pDrawable = (DrawablePtr)pResource;
525    DRIScreenPrivPtr    pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen);
526    DRIDrawablePrivPtr  pDRIDrawablePriv = NULL;
527    WindowPtr           pWin = NULL;
528    PixmapPtr           pPix = NULL;
529
530    if (pDrawable->type == DRAWABLE_WINDOW) {
531        pWin = (WindowPtr)pDrawable;
532        pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
533    } else if (pDrawable->type == DRAWABLE_PIXMAP) {
534        pPix = (PixmapPtr)pDrawable;
535        pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix);
536    }
537
538    if (pDRIDrawablePriv == NULL) {
539	/*
540	 * We reuse __func__ and the resource type for the GLXPixmap code.
541	 * Attempt to free a pixmap buffer associated with the resource
542	 * if possible.
543	 */
544	return DRIFreePixmapImp(pDrawable);
545    }
546
547    if (pDRIDrawablePriv->drawableIndex != -1) {
548        /* release drawable table entry */
549        pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL;
550    }
551
552    if (pDRIDrawablePriv->sid != 0) {
553	DRISurfaceNotify(pDRIDrawablePriv->sid, AppleDRISurfaceNotifyDestroyed);
554    }
555
556
557    if (pDRIDrawablePriv->notifiers != NULL)
558        x_hook_free(pDRIDrawablePriv->notifiers);
559
560    free(pDRIDrawablePriv);
561
562    if (pDrawable->type == DRAWABLE_WINDOW) {
563	dixSetPrivate(&pWin->devPrivates, DRIWindowPrivKey, NULL);
564    } else if (pDrawable->type == DRAWABLE_PIXMAP) {
565	dixSetPrivate(&pPix->devPrivates, DRIPixmapPrivKey, NULL);
566    }
567
568    --pDRIPriv->nrWindows;
569
570    return TRUE;
571}
572
573void
574DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg)
575{
576    ScreenPtr pScreen = pWin->drawable.pScreen;
577    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
578    DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
579
580    if (pDRIDrawablePriv) {
581        /* FIXME: something? */
582    }
583
584    pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures;
585
586    (*pScreen->WindowExposures)(pWin, prgn, bsreg);
587
588    pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
589    pScreen->WindowExposures = DRIWindowExposures;
590}
591
592void
593DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
594{
595    ScreenPtr pScreen = pWin->drawable.pScreen;
596    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
597    DRIDrawablePrivPtr pDRIDrawablePriv;
598
599    if (pDRIPriv->nrWindows > 0) {
600       pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin);
601       if (pDRIDrawablePriv != NULL) {
602            DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable);
603       }
604    }
605
606    /* unwrap */
607    pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow;
608
609    /* call lower layers */
610    (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
611
612    /* rewrap */
613    pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
614    pScreen->CopyWindow = DRICopyWindow;
615}
616
617int
618DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
619{
620    ScreenPtr pScreen = pParent->drawable.pScreen;
621    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
622    int returnValue;
623
624    /* unwrap */
625    pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree;
626
627    /* call lower layers */
628    returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
629
630    /* rewrap */
631    pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
632    pScreen->ValidateTree = DRIValidateTree;
633
634    return returnValue;
635}
636
637void
638DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
639{
640    ScreenPtr pScreen;
641    DRIScreenPrivPtr pDRIPriv;
642
643    if (pParent) {
644        pScreen = pParent->drawable.pScreen;
645    } else {
646        pScreen = pChild->drawable.pScreen;
647    }
648    pDRIPriv = DRI_SCREEN_PRIV(pScreen);
649
650    if (pDRIPriv->wrap.PostValidateTree) {
651        /* unwrap */
652        pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree;
653
654        /* call lower layers */
655        (*pScreen->PostValidateTree)(pParent, pChild, kind);
656
657        /* rewrap */
658        pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
659        pScreen->PostValidateTree = DRIPostValidateTree;
660    }
661}
662
663void
664DRIClipNotify(WindowPtr pWin, int dx, int dy)
665{
666    ScreenPtr pScreen = pWin->drawable.pScreen;
667    DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
668    DRIDrawablePrivPtr  pDRIDrawablePriv;
669
670    if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) {
671        DRIUpdateSurface(pDRIDrawablePriv, &pWin->drawable);
672    }
673
674    if (pDRIPriv->wrap.ClipNotify) {
675        pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify;
676
677        (*pScreen->ClipNotify)(pWin, dx, dy);
678
679        pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
680        pScreen->ClipNotify = DRIClipNotify;
681    }
682}
683
684/* This lets us get at the unwrapped functions so that they can correctly
685 * call the lower level functions, and choose whether they will be
686 * called at every level of recursion (eg in validatetree).
687 */
688DRIWrappedFuncsRec *
689DRIGetWrappedFuncs(ScreenPtr pScreen)
690{
691    return &(DRI_SCREEN_PRIV(pScreen)->wrap);
692}
693
694void
695DRIQueryVersion(int *majorVersion,
696                int *minorVersion,
697                int *patchVersion)
698{
699    *majorVersion = APPLE_DRI_MAJOR_VERSION;
700    *minorVersion = APPLE_DRI_MINOR_VERSION;
701    *patchVersion = APPLE_DRI_PATCH_VERSION;
702}
703
704/*
705 * Note: this also cleans up the hash table in addition to notifying clients.
706 * The sid/surface-id should not be used after this, because it will be
707 * invalid.
708 */
709void
710DRISurfaceNotify(xp_surface_id id, int kind)
711{
712    DRIDrawablePrivPtr pDRIDrawablePriv = NULL;
713    DRISurfaceNotifyArg arg;
714
715    arg.id = id;
716    arg.kind = kind;
717
718    if (surface_hash != NULL)
719    {
720        pDRIDrawablePriv = x_hash_table_lookup(surface_hash,
721                                               x_cvt_uint_to_vptr(id), NULL);
722    }
723
724    if (pDRIDrawablePriv == NULL)
725        return;
726
727    if (kind == AppleDRISurfaceNotifyDestroyed)
728    {
729	x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(id));
730    }
731
732    x_hook_run(pDRIDrawablePriv->notifiers, &arg);
733
734    if (kind == AppleDRISurfaceNotifyDestroyed)
735    {
736	xp_error error;
737
738	error = xp_destroy_surface(pDRIDrawablePriv->sid);
739
740	if(error)
741	    ErrorF("%s: xp_destroy_surface failed: %d\n", __func__, error);
742
743	/* Guard against reuse, even though we are freeing after this. */
744	pDRIDrawablePriv->sid = 0;
745
746        FreeResourceByType(pDRIDrawablePriv->pDraw->id,
747                           DRIDrawablePrivResType, FALSE);
748    }
749}
750
751/*
752 * This creates a shared memory buffer for use with GLXPixmaps
753 * and AppleSGLX.
754 */
755Bool DRICreatePixmap(ScreenPtr pScreen, Drawable id,
756		     DrawablePtr pDrawable, char *path,
757		     size_t pathmax)
758{
759    DRIPixmapBufferPtr shared;
760    PixmapPtr pPix;
761
762    if(pDrawable->type != DRAWABLE_PIXMAP)
763	return FALSE;
764
765    pPix = (PixmapPtr)pDrawable;
766
767    shared = malloc(sizeof(*shared));
768    if(NULL == shared) {
769        FatalError("failed to allocate DRIPixmapBuffer in %s\n", __func__);
770    }
771
772    shared->pDrawable = pDrawable;
773    shared->refCount = 1;
774
775    if(pDrawable->bitsPerPixel >= 24) {
776	shared->bytesPerPixel = 4;
777    } else if(pDrawable->bitsPerPixel <= 16) {
778	shared->bytesPerPixel = 2;
779    }
780
781    shared->width = pDrawable->width;
782    shared->height = pDrawable->height;
783
784    if(-1 == snprintf(shared->shmPath, sizeof(shared->shmPath),
785                      "%d_0x%lx", getpid(),
786                      (unsigned long)id)) {
787        FatalError("buffer overflow in %s\n", __func__);
788    }
789
790    shared->fd = shm_open(shared->shmPath,
791                          O_RDWR | O_EXCL | O_CREAT,
792                          S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
793
794    if(-1 == shared->fd) {
795	free(shared);
796        return FALSE;
797    }
798
799    shared->length = shared->width * shared->height * shared->bytesPerPixel;
800
801    if(-1 == ftruncate(shared->fd, shared->length)) {
802	ErrorF("failed to ftruncate (extend) file.");
803	shm_unlink(shared->shmPath);
804	close(shared->fd);
805	free(shared);
806	return FALSE;
807    }
808
809    shared->buffer = mmap(NULL, shared->length,
810                          PROT_READ | PROT_WRITE,
811                          MAP_FILE | MAP_SHARED, shared->fd, 0);
812
813    if(MAP_FAILED == shared->buffer) {
814	ErrorF("failed to mmap shared memory.");
815	shm_unlink(shared->shmPath);
816	close(shared->fd);
817	free(shared);
818	return FALSE;
819    }
820
821    strncpy(path, shared->shmPath, pathmax);
822    path[pathmax - 1] = '\0';
823
824    dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, shared);
825
826    AddResource(id, DRIDrawablePrivResType, (pointer)pDrawable);
827
828    return TRUE;
829}
830
831
832Bool DRIGetPixmapData(DrawablePtr pDrawable, int *width, int *height,
833		      int *pitch, int *bpp, void **ptr) {
834    PixmapPtr pPix;
835    DRIPixmapBufferPtr shared;
836
837    if(pDrawable->type != DRAWABLE_PIXMAP)
838	return FALSE;
839
840    pPix = (PixmapPtr)pDrawable;
841
842    shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey);
843
844    if(NULL == shared)
845	return FALSE;
846
847    assert(pDrawable->width == shared->width);
848    assert(pDrawable->height == shared->height);
849
850    *width = shared->width;
851    *height = shared->height;
852    *bpp = shared->bytesPerPixel;
853    *pitch = shared->width * shared->bytesPerPixel;
854    *ptr = shared->buffer;
855
856    return TRUE;
857}
858
859static Bool
860DRIFreePixmapImp(DrawablePtr pDrawable) {
861    DRIPixmapBufferPtr shared;
862    PixmapPtr pPix;
863
864    if(pDrawable->type != DRAWABLE_PIXMAP)
865	return FALSE;
866
867    pPix = (PixmapPtr)pDrawable;
868
869    shared = dixLookupPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey);
870
871    if(NULL == shared)
872	return FALSE;
873
874    close(shared->fd);
875    munmap(shared->buffer, shared->length);
876    shm_unlink(shared->shmPath);
877    free(shared);
878
879    dixSetPrivate(&pPix->devPrivates, DRIPixmapBufferPrivKey, (pointer)NULL);
880
881    return TRUE;
882}
883
884void
885DRIDestroyPixmap(DrawablePtr pDrawable) {
886    if(DRIFreePixmapImp(pDrawable))
887	FreeResourceByType(pDrawable->id, DRIDrawablePrivResType, FALSE);
888
889}
890