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