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