xref: /OK3568_Linux_fs/external/xserver/hw/xquartz/xpr/dri.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 
72 static DevPrivateKeyRec DRIScreenPrivKeyRec;
73 #define DRIScreenPrivKey       (&DRIScreenPrivKeyRec)
74 static DevPrivateKeyRec DRIWindowPrivKeyRec;
75 #define DRIWindowPrivKey       (&DRIWindowPrivKeyRec)
76 static DevPrivateKeyRec DRIPixmapPrivKeyRec;
77 #define DRIPixmapPrivKey       (&DRIPixmapPrivKeyRec)
78 static DevPrivateKeyRec DRIPixmapBufferPrivKeyRec;
79 #define DRIPixmapBufferPrivKey (&DRIPixmapBufferPrivKeyRec)
80 
81 static RESTYPE DRIDrawablePrivResType;
82 
83 static x_hash_table *surface_hash;      /* maps surface ids -> drawablePrivs */
84 
85 static Bool
86 DRIFreePixmapImp(DrawablePtr pDrawable);
87 
88 typedef 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 
100 Bool
DRIScreenInit(ScreenPtr pScreen)101 DRIScreenInit(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 
133 Bool
DRIFinishScreenInit(ScreenPtr pScreen)134 DRIFinishScreenInit(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 
150 void
DRICloseScreen(ScreenPtr pScreen)151 DRICloseScreen(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 
161 Bool
DRIExtensionInit(void)162 DRIExtensionInit(void)
163 {
164     DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete,
165                                                    "DRIDrawable");
166 
167     return DRIDrawablePrivResType != 0;
168 }
169 
170 void
DRIReset(void)171 DRIReset(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 
182 Bool
DRIQueryDirectRenderingCapable(ScreenPtr pScreen,Bool * isCapable)183 DRIQueryDirectRenderingCapable(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 
195 Bool
DRIAuthConnection(ScreenPtr pScreen,unsigned int magic)196 DRIAuthConnection(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 
208 static void
DRIUpdateSurface(DRIDrawablePrivPtr pDRIDrawablePriv,DrawablePtr pDraw)209 DRIUpdateSurface(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. */
253 static DRIDrawablePrivPtr
CreateSurfaceForWindow(ScreenPtr pScreen,WindowPtr pWin,xp_window_id * widPtr)254 CreateSurfaceForWindow(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. */
317 static DRIDrawablePrivPtr
CreateSurfaceForPixmap(ScreenPtr pScreen,PixmapPtr pPix)318 CreateSurfaceForPixmap(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 
360 Bool
DRICreateSurface(ScreenPtr pScreen,Drawable id,DrawablePtr pDrawable,xp_client_id client_id,xp_surface_id * surface_id,unsigned int ret_key[2],void (* notify)(void * arg,void * data),void * notify_data)361 DRICreateSurface(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 
464 Bool
DRIDestroySurface(ScreenPtr pScreen,Drawable id,DrawablePtr pDrawable,void (* notify)(void *,void *),void * notify_data)465 DRIDestroySurface(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  */
514 Bool
DRIDrawablePrivDelete(void * pResource,XID id)515 DRIDrawablePrivDelete(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 
568 void
DRICopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)569 DRICopyWindow(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 
592 void
DRIClipNotify(WindowPtr pWin,int dx,int dy)593 DRIClipNotify(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  */
616 DRIWrappedFuncsRec *
DRIGetWrappedFuncs(ScreenPtr pScreen)617 DRIGetWrappedFuncs(ScreenPtr pScreen)
618 {
619     return &(DRI_SCREEN_PRIV(pScreen)->wrap);
620 }
621 
622 void
DRIQueryVersion(int * majorVersion,int * minorVersion,int * patchVersion)623 DRIQueryVersion(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  */
637 void
DRISurfaceNotify(xp_surface_id id,int kind)638 DRISurfaceNotify(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  */
680 Bool
DRICreatePixmap(ScreenPtr pScreen,Drawable id,DrawablePtr pDrawable,char * path,size_t pathmax)681 DRICreatePixmap(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 
757 Bool
DRIGetPixmapData(DrawablePtr pDrawable,int * width,int * height,int * pitch,int * bpp,void ** ptr)758 DRIGetPixmapData(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 
786 static Bool
DRIFreePixmapImp(DrawablePtr pDrawable)787 DRIFreePixmapImp(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 
812 void
DRIDestroyPixmap(DrawablePtr pDrawable)813 DRIDestroyPixmap(DrawablePtr pDrawable)
814 {
815     if (DRIFreePixmapImp(pDrawable))
816         FreeResourceByType(pDrawable->id, DRIDrawablePrivResType, FALSE);
817 
818 }
819