indirect.c (18682B)
1 /* 2 * GLX implementation that uses Apple's OpenGL.framework 3 * (Indirect rendering path -- it's also used for some direct mode code too) 4 * 5 * Copyright (c) 2007-2012 Apple Inc. 6 * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. 7 * Copyright (c) 2002 Greg Parker. All Rights Reserved. 8 * 9 * Portions of this file are copied from Mesa's xf86glx.c, 10 * which contains the following copyright: 11 * 12 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 13 * All Rights Reserved. 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a 16 * copy of this software and associated documentation files (the "Software"), 17 * to deal in the Software without restriction, including without limitation 18 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 * and/or sell copies of the Software, and to permit persons to whom the 20 * Software is furnished to do so, subject to the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be included in 23 * all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 * DEALINGS IN THE SOFTWARE. 32 */ 33 34 #ifdef HAVE_DIX_CONFIG_H 35 #include <dix-config.h> 36 #endif 37 38 #include <dlfcn.h> 39 40 #include <OpenGL/OpenGL.h> 41 #include <OpenGL/gl.h> /* Just to prevent glxserver.h from loading mesa's and colliding with OpenGL.h */ 42 43 #include <X11/Xproto.h> 44 #include <GL/glxproto.h> 45 46 #include <glxserver.h> 47 #include <glxutil.h> 48 49 #include "x-hash.h" 50 51 #include "visualConfigs.h" 52 #include "dri.h" 53 #include "extension_string.h" 54 55 #include "darwin.h" 56 #define GLAQUA_DEBUG_MSG(msg, args ...) ASL_LOG(ASL_LEVEL_DEBUG, "GLXAqua", \ 57 msg, \ 58 ## args) 59 60 __GLXprovider * 61 GlxGetDRISWrastProvider(void); 62 63 static void 64 setup_dispatch_table(void); 65 GLuint 66 __glFloorLog2(GLuint val); 67 void 68 warn_func(void * p1, char *format, ...); 69 70 // some prototypes 71 static __GLXscreen * 72 __glXAquaScreenProbe(ScreenPtr pScreen); 73 static __GLXdrawable * 74 __glXAquaScreenCreateDrawable(ClientPtr client, __GLXscreen *screen, 75 DrawablePtr pDraw, XID drawId, int type, 76 XID glxDrawId, 77 __GLXconfig *conf); 78 79 static void 80 __glXAquaContextDestroy(__GLXcontext *baseContext); 81 static int 82 __glXAquaContextMakeCurrent(__GLXcontext *baseContext); 83 static int 84 __glXAquaContextLoseCurrent(__GLXcontext *baseContext); 85 static int 86 __glXAquaContextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 87 unsigned long mask); 88 89 static CGLPixelFormatObj 90 makeFormat(__GLXconfig *conf); 91 92 __GLXprovider __glXDRISWRastProvider = { 93 __glXAquaScreenProbe, 94 "Core OpenGL", 95 NULL 96 }; 97 98 typedef struct __GLXAquaScreen __GLXAquaScreen; 99 typedef struct __GLXAquaContext __GLXAquaContext; 100 typedef struct __GLXAquaDrawable __GLXAquaDrawable; 101 102 /* 103 * The following structs must keep the base as the first member. 104 * It's used to treat the start of the struct as a different struct 105 * in GLX. 106 * 107 * Note: these structs should be initialized with xcalloc or memset 108 * prior to usage, and some of them require initializing 109 * the base with function pointers. 110 */ 111 struct __GLXAquaScreen { 112 __GLXscreen base; 113 }; 114 115 struct __GLXAquaContext { 116 __GLXcontext base; 117 CGLContextObj ctx; 118 CGLPixelFormatObj pixelFormat; 119 xp_surface_id sid; 120 unsigned isAttached : 1; 121 }; 122 123 struct __GLXAquaDrawable { 124 __GLXdrawable base; 125 DrawablePtr pDraw; 126 xp_surface_id sid; 127 __GLXAquaContext *context; 128 }; 129 130 static __GLXcontext * 131 __glXAquaScreenCreateContext(__GLXscreen *screen, 132 __GLXconfig *conf, 133 __GLXcontext *baseShareContext, 134 unsigned num_attribs, 135 const uint32_t *attribs, 136 int *error) 137 { 138 __GLXAquaContext *context; 139 __GLXAquaContext *shareContext = (__GLXAquaContext *)baseShareContext; 140 CGLError gl_err; 141 142 /* Unused (for now?) */ 143 (void)num_attribs; 144 (void)attribs; 145 (void)error; 146 147 GLAQUA_DEBUG_MSG("glXAquaScreenCreateContext\n"); 148 149 context = calloc(1, sizeof(__GLXAquaContext)); 150 151 if (context == NULL) 152 return NULL; 153 154 memset(context, 0, sizeof *context); 155 156 context->base.pGlxScreen = screen; 157 context->base.config = conf; 158 context->base.destroy = __glXAquaContextDestroy; 159 context->base.makeCurrent = __glXAquaContextMakeCurrent; 160 context->base.loseCurrent = __glXAquaContextLoseCurrent; 161 context->base.copy = __glXAquaContextCopy; 162 /*FIXME verify that the context->base is fully initialized. */ 163 164 context->pixelFormat = makeFormat(conf); 165 166 if (!context->pixelFormat) { 167 free(context); 168 return NULL; 169 } 170 171 context->ctx = NULL; 172 gl_err = CGLCreateContext(context->pixelFormat, 173 shareContext ? shareContext->ctx : NULL, 174 &context->ctx); 175 176 if (gl_err != 0) { 177 ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err)); 178 CGLDestroyPixelFormat(context->pixelFormat); 179 free(context); 180 return NULL; 181 } 182 183 setup_dispatch_table(); 184 GLAQUA_DEBUG_MSG("glAquaCreateContext done\n"); 185 186 return &context->base; 187 } 188 189 /* maps from surface id -> list of __GLcontext */ 190 static x_hash_table *surface_hash; 191 192 static void 193 __glXAquaContextDestroy(__GLXcontext *baseContext) 194 { 195 x_list *lst; 196 197 __GLXAquaContext *context = (__GLXAquaContext *)baseContext; 198 199 GLAQUA_DEBUG_MSG("glAquaContextDestroy (ctx %p)\n", baseContext); 200 if (context != NULL) { 201 if (context->sid != 0 && surface_hash != NULL) { 202 lst = 203 x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr( 204 context->sid), NULL); 205 lst = x_list_remove(lst, context); 206 x_hash_table_insert(surface_hash, x_cvt_uint_to_vptr( 207 context->sid), lst); 208 } 209 210 if (context->ctx != NULL) 211 CGLDestroyContext(context->ctx); 212 213 if (context->pixelFormat != NULL) 214 CGLDestroyPixelFormat(context->pixelFormat); 215 216 free(context); 217 } 218 } 219 220 static int 221 __glXAquaContextLoseCurrent(__GLXcontext *baseContext) 222 { 223 CGLError gl_err; 224 225 GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%p)\n", baseContext); 226 227 gl_err = CGLSetCurrentContext(NULL); 228 if (gl_err != 0) 229 ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); 230 231 /* 232 * There should be no need to set __glXLastContext to NULL here, because 233 * glxcmds.c does it as part of the context cache flush after calling 234 * this. 235 */ 236 237 return GL_TRUE; 238 } 239 240 /* Called when a surface is destroyed as a side effect of destroying 241 the window it's attached to. */ 242 static void 243 surface_notify(void *_arg, void *data) 244 { 245 DRISurfaceNotifyArg *arg = (DRISurfaceNotifyArg *)_arg; 246 __GLXAquaDrawable *draw = (__GLXAquaDrawable *)data; 247 __GLXAquaContext *context; 248 x_list *lst; 249 if (_arg == NULL || data == NULL) { 250 ErrorF("surface_notify called with bad params"); 251 return; 252 } 253 254 GLAQUA_DEBUG_MSG("surface_notify(%p, %p)\n", _arg, data); 255 switch (arg->kind) { 256 case AppleDRISurfaceNotifyDestroyed: 257 if (surface_hash != NULL) 258 x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(arg->id)); 259 draw->pDraw = NULL; 260 draw->sid = 0; 261 break; 262 263 case AppleDRISurfaceNotifyChanged: 264 if (surface_hash != NULL) { 265 lst = 266 x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr( 267 arg->id), NULL); 268 for (; lst != NULL; lst = lst->next) { 269 context = lst->data; 270 xp_update_gl_context(context->ctx); 271 } 272 } 273 break; 274 275 default: 276 ErrorF("surface_notify: unknown kind %d\n", arg->kind); 277 break; 278 } 279 } 280 281 static BOOL 282 attach(__GLXAquaContext *context, __GLXAquaDrawable *draw) 283 { 284 DrawablePtr pDraw; 285 286 GLAQUA_DEBUG_MSG("attach(%p, %p)\n", context, draw); 287 288 if (NULL == context || NULL == draw) 289 return TRUE; 290 291 pDraw = draw->base.pDraw; 292 293 if (NULL == pDraw) { 294 ErrorF("%s:%s() pDraw is NULL!\n", __FILE__, __func__); 295 return TRUE; 296 } 297 298 if (draw->sid == 0) { 299 //if (!quartzProcs->CreateSurface(pDraw->pScreen, pDraw->id, pDraw, 300 if (!DRICreateSurface(pDraw->pScreen, pDraw->id, pDraw, 301 0, &draw->sid, NULL, 302 surface_notify, draw)) 303 return TRUE; 304 draw->pDraw = pDraw; 305 } 306 307 if (!context->isAttached || context->sid != draw->sid) { 308 x_list *lst; 309 310 if (xp_attach_gl_context(context->ctx, draw->sid) != Success) { 311 //quartzProcs->DestroySurface(pDraw->pScreen, pDraw->id, pDraw, 312 DRIDestroySurface(pDraw->pScreen, pDraw->id, pDraw, 313 surface_notify, draw); 314 if (surface_hash != NULL) 315 x_hash_table_remove(surface_hash, 316 x_cvt_uint_to_vptr(draw->sid)); 317 318 draw->sid = 0; 319 return TRUE; 320 } 321 322 context->isAttached = TRUE; 323 context->sid = draw->sid; 324 325 if (surface_hash == NULL) 326 surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL); 327 328 lst = 329 x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr( 330 context->sid), NULL); 331 if (x_list_find(lst, context) == NULL) { 332 lst = x_list_prepend(lst, context); 333 x_hash_table_insert(surface_hash, x_cvt_uint_to_vptr( 334 context->sid), lst); 335 } 336 337 GLAQUA_DEBUG_MSG("attached 0x%x to 0x%x\n", (unsigned int)pDraw->id, 338 (unsigned int)draw->sid); 339 } 340 341 draw->context = context; 342 343 return FALSE; 344 } 345 346 #if 0 // unused 347 static void 348 unattach(__GLXAquaContext *context) 349 { 350 x_list *lst; 351 GLAQUA_DEBUG_MSG("unattach\n"); 352 if (context == NULL) { 353 ErrorF("Tried to unattach a null context\n"); 354 return; 355 } 356 if (context->isAttached) { 357 GLAQUA_DEBUG_MSG("unattaching\n"); 358 359 if (surface_hash != NULL) { 360 lst = x_hash_table_lookup(surface_hash, (void *)context->sid, 361 NULL); 362 lst = x_list_remove(lst, context); 363 x_hash_table_insert(surface_hash, (void *)context->sid, lst); 364 } 365 366 CGLClearDrawable(context->ctx); 367 context->isAttached = FALSE; 368 context->sid = 0; 369 } 370 } 371 #endif 372 373 static int 374 __glXAquaContextMakeCurrent(__GLXcontext *baseContext) 375 { 376 CGLError gl_err; 377 __GLXAquaContext *context = (__GLXAquaContext *)baseContext; 378 __GLXAquaDrawable *drawPriv = (__GLXAquaDrawable *)context->base.drawPriv; 379 380 GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%p)\n", baseContext); 381 382 if (context->base.drawPriv != context->base.readPriv) 383 return 0; 384 385 if (attach(context, drawPriv)) 386 return /*error*/ 0; 387 388 gl_err = CGLSetCurrentContext(context->ctx); 389 if (gl_err != 0) 390 ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); 391 392 return gl_err == 0; 393 } 394 395 static int 396 __glXAquaContextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 397 unsigned long mask) 398 { 399 CGLError gl_err; 400 401 __GLXAquaContext *dst = (__GLXAquaContext *)baseDst; 402 __GLXAquaContext *src = (__GLXAquaContext *)baseSrc; 403 404 GLAQUA_DEBUG_MSG("GLXAquaContextCopy\n"); 405 406 gl_err = CGLCopyContext(src->ctx, dst->ctx, mask); 407 if (gl_err != 0) 408 ErrorF("CGLCopyContext error: %s\n", CGLErrorString(gl_err)); 409 410 return gl_err == 0; 411 } 412 413 /* Drawing surface notification callbacks */ 414 static GLboolean 415 __glXAquaDrawableSwapBuffers(ClientPtr client, __GLXdrawable *base) 416 { 417 CGLError err; 418 __GLXAquaDrawable *drawable; 419 420 // GLAQUA_DEBUG_MSG("glAquaDrawableSwapBuffers(%p)\n",base); 421 422 if (!base) { 423 ErrorF("%s passed NULL\n", __func__); 424 return GL_FALSE; 425 } 426 427 drawable = (__GLXAquaDrawable *)base; 428 429 if (NULL == drawable->context) { 430 ErrorF("%s called with a NULL->context for drawable %p!\n", 431 __func__, (void *)drawable); 432 return GL_FALSE; 433 } 434 435 err = CGLFlushDrawable(drawable->context->ctx); 436 437 if (kCGLNoError != err) { 438 ErrorF("CGLFlushDrawable error: %s in %s\n", CGLErrorString(err), 439 __func__); 440 return GL_FALSE; 441 } 442 443 return GL_TRUE; 444 } 445 446 static CGLPixelFormatObj 447 makeFormat(__GLXconfig *conf) 448 { 449 CGLPixelFormatAttribute attr[64]; 450 CGLPixelFormatObj fobj; 451 GLint formats; 452 CGLError error; 453 int i = 0; 454 455 if (conf->doubleBufferMode) 456 attr[i++] = kCGLPFADoubleBuffer; 457 458 if (conf->stereoMode) 459 attr[i++] = kCGLPFAStereo; 460 461 attr[i++] = kCGLPFAColorSize; 462 attr[i++] = conf->redBits + conf->greenBits + conf->blueBits; 463 attr[i++] = kCGLPFAAlphaSize; 464 attr[i++] = conf->alphaBits; 465 466 if ((conf->accumRedBits + conf->accumGreenBits + conf->accumBlueBits + 467 conf->accumAlphaBits) > 0) { 468 469 attr[i++] = kCGLPFAAccumSize; 470 attr[i++] = conf->accumRedBits + conf->accumGreenBits 471 + conf->accumBlueBits + conf->accumAlphaBits; 472 } 473 474 attr[i++] = kCGLPFADepthSize; 475 attr[i++] = conf->depthBits; 476 477 if (conf->stencilBits) { 478 attr[i++] = kCGLPFAStencilSize; 479 attr[i++] = conf->stencilBits; 480 } 481 482 if (conf->numAuxBuffers > 0) { 483 attr[i++] = kCGLPFAAuxBuffers; 484 attr[i++] = conf->numAuxBuffers; 485 } 486 487 if (conf->sampleBuffers > 0) { 488 attr[i++] = kCGLPFASampleBuffers; 489 attr[i++] = conf->sampleBuffers; 490 attr[i++] = kCGLPFASamples; 491 attr[i++] = conf->samples; 492 } 493 494 attr[i] = 0; 495 496 error = CGLChoosePixelFormat(attr, &fobj, &formats); 497 if (error) { 498 ErrorF("error: creating pixel format %s\n", CGLErrorString(error)); 499 return NULL; 500 } 501 502 return fobj; 503 } 504 505 static void 506 __glXAquaScreenDestroy(__GLXscreen *screen) 507 { 508 509 GLAQUA_DEBUG_MSG("glXAquaScreenDestroy(%p)\n", screen); 510 __glXScreenDestroy(screen); 511 512 free(screen); 513 } 514 515 /* This is called by __glXInitScreens(). */ 516 static __GLXscreen * 517 __glXAquaScreenProbe(ScreenPtr pScreen) 518 { 519 __GLXAquaScreen *screen; 520 521 GLAQUA_DEBUG_MSG("glXAquaScreenProbe\n"); 522 523 if (pScreen == NULL) 524 return NULL; 525 526 screen = calloc(1, sizeof *screen); 527 528 if (NULL == screen) 529 return NULL; 530 531 screen->base.destroy = __glXAquaScreenDestroy; 532 screen->base.createContext = __glXAquaScreenCreateContext; 533 screen->base.createDrawable = __glXAquaScreenCreateDrawable; 534 screen->base.swapInterval = /*FIXME*/ NULL; 535 screen->base.pScreen = pScreen; 536 537 screen->base.fbconfigs = __glXAquaCreateVisualConfigs( 538 &screen->base.numFBConfigs, pScreen->myNum); 539 540 __glXInitExtensionEnableBits(screen->base.glx_enable_bits); 541 __glXScreenInit(&screen->base, pScreen); 542 543 return &screen->base; 544 } 545 546 #if 0 // unused 547 static void 548 __glXAquaDrawableCopySubBuffer(__GLXdrawable *drawable, 549 int x, int y, int w, int h) 550 { 551 /*TODO finish me*/ 552 } 553 #endif 554 555 static void 556 __glXAquaDrawableDestroy(__GLXdrawable *base) 557 { 558 /* gstaplin: base is the head of the structure, so it's at the same 559 * offset in memory. 560 * Is this safe with strict aliasing? I noticed that the other dri code 561 * does this too... 562 */ 563 __GLXAquaDrawable *glxPriv = (__GLXAquaDrawable *)base; 564 565 GLAQUA_DEBUG_MSG("TRACE"); 566 567 /* It doesn't work to call DRIDestroySurface here, the drawable's 568 already gone.. But dri.c notices the window destruction and 569 frees the surface itself. */ 570 571 /*gstaplin: verify the statement above. The surface destroy 572 *messages weren't making it through, and may still not be. 573 *We need a good test case for surface creation and destruction. 574 *We also need a good way to enable introspection on the server 575 *to validate the test, beyond using gdb with print. 576 */ 577 578 free(glxPriv); 579 } 580 581 static __GLXdrawable * 582 __glXAquaScreenCreateDrawable(ClientPtr client, 583 __GLXscreen *screen, 584 DrawablePtr pDraw, 585 XID drawId, 586 int type, 587 XID glxDrawId, 588 __GLXconfig *conf) 589 { 590 __GLXAquaDrawable *glxPriv; 591 592 glxPriv = malloc(sizeof *glxPriv); 593 594 if (glxPriv == NULL) 595 return NULL; 596 597 memset(glxPriv, 0, sizeof *glxPriv); 598 599 if (!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, glxDrawId, 600 conf)) { 601 free(glxPriv); 602 return NULL; 603 } 604 605 glxPriv->base.destroy = __glXAquaDrawableDestroy; 606 glxPriv->base.swapBuffers = __glXAquaDrawableSwapBuffers; 607 glxPriv->base.copySubBuffer = NULL; /* __glXAquaDrawableCopySubBuffer; */ 608 609 glxPriv->pDraw = pDraw; 610 glxPriv->sid = 0; 611 glxPriv->context = NULL; 612 613 return &glxPriv->base; 614 } 615 616 // Extra goodies for glx 617 618 GLuint 619 __glFloorLog2(GLuint val) 620 { 621 int c = 0; 622 623 while (val > 1) { 624 c++; 625 val >>= 1; 626 } 627 return c; 628 } 629 630 #ifndef OPENGL_FRAMEWORK_PATH 631 #define OPENGL_FRAMEWORK_PATH \ 632 "/System/Library/Frameworks/OpenGL.framework/OpenGL" 633 #endif 634 635 static void *opengl_framework_handle; 636 637 static glx_func_ptr 638 get_proc_address(const char *sym) 639 { 640 return (glx_func_ptr) dlsym(opengl_framework_handle, sym); 641 } 642 643 static void 644 setup_dispatch_table(void) 645 { 646 const char *opengl_framework_path; 647 648 if (opengl_framework_handle) { 649 return; 650 } 651 652 opengl_framework_path = getenv("OPENGL_FRAMEWORK_PATH"); 653 if (!opengl_framework_path) { 654 opengl_framework_path = OPENGL_FRAMEWORK_PATH; 655 } 656 657 (void)dlerror(); /*drain dlerror */ 658 opengl_framework_handle = dlopen(opengl_framework_path, RTLD_LOCAL); 659 660 if (!opengl_framework_handle) { 661 ErrorF("unable to dlopen %s : %s, using RTLD_DEFAULT\n", 662 opengl_framework_path, dlerror()); 663 opengl_framework_handle = RTLD_DEFAULT; 664 } 665 666 __glXsetGetProcAddress(get_proc_address); 667 }