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