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