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