2 * GLX implementation that uses Apple's OpenGL.framework
3 * (Indirect rendering path -- it's also used for some direct mode code too)
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.
9 * Portions of this file are copied from Mesa's xf86glx.c,
10 * which contains the following copyright:
12 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
13 * All Rights Reserved.
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:
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
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.
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
38 #include <AvailabilityMacros.h>
42 #include <OpenGL/OpenGL.h>
43 #include <OpenGL/gl.h> /* Just to prevent glxserver.h from loading mesa's and colliding with OpenGL.h */
45 #include <X11/Xproto.h>
46 #include <GL/glxproto.h>
48 #include <glxserver.h>
53 #include "visualConfigs.h"
57 #define GLAQUA_DEBUG_MSG(msg, args ...) ASL_LOG(ASL_LEVEL_DEBUG, "GLXAqua", \
62 GlxGetDRISWrastProvider(void);
65 setup_dispatch_table(void);
67 __glFloorLog2(GLuint val
);
69 warn_func(void * p1
, char *format
, ...);
73 __glXAquaScreenProbe(ScreenPtr pScreen
);
74 static __GLXdrawable
*
75 __glXAquaScreenCreateDrawable(ClientPtr client
, __GLXscreen
*screen
,
76 DrawablePtr pDraw
, XID drawId
, int type
,
81 __glXAquaContextDestroy(__GLXcontext
*baseContext
);
83 __glXAquaContextMakeCurrent(__GLXcontext
*baseContext
);
85 __glXAquaContextLoseCurrent(__GLXcontext
*baseContext
);
87 __glXAquaContextCopy(__GLXcontext
*baseDst
, __GLXcontext
*baseSrc
,
90 static CGLPixelFormatObj
91 makeFormat(__GLXconfig
*conf
);
93 __GLXprovider __glXDRISWRastProvider
= {
99 typedef struct __GLXAquaScreen __GLXAquaScreen
;
100 typedef struct __GLXAquaContext __GLXAquaContext
;
101 typedef struct __GLXAquaDrawable __GLXAquaDrawable
;
104 * The following structs must keep the base as the first member.
105 * It's used to treat the start of the struct as a different struct
108 * Note: these structs should be initialized with xcalloc or memset
109 * prior to usage, and some of them require initializing
110 * the base with function pointers.
112 struct __GLXAquaScreen
{
118 struct __GLXAquaContext
{
121 CGLPixelFormatObj pixelFormat
;
123 unsigned isAttached
: 1;
126 struct __GLXAquaDrawable
{
130 __GLXAquaContext
*context
;
133 static __GLXcontext
*
134 __glXAquaScreenCreateContext(__GLXscreen
*screen
,
136 __GLXcontext
*baseShareContext
,
137 unsigned num_attribs
,
138 const uint32_t *attribs
,
141 __GLXAquaContext
*context
;
142 __GLXAquaContext
*shareContext
= (__GLXAquaContext
*)baseShareContext
;
145 /* Unused (for now?) */
150 GLAQUA_DEBUG_MSG("glXAquaScreenCreateContext\n");
152 context
= calloc(1, sizeof(__GLXAquaContext
));
157 memset(context
, 0, sizeof *context
);
159 context
->base
.pGlxScreen
= screen
;
161 context
->base
.destroy
= __glXAquaContextDestroy
;
162 context
->base
.makeCurrent
= __glXAquaContextMakeCurrent
;
163 context
->base
.loseCurrent
= __glXAquaContextLoseCurrent
;
164 context
->base
.copy
= __glXAquaContextCopy
;
165 /*FIXME verify that the context->base is fully initialized. */
167 context
->pixelFormat
= makeFormat(conf
);
169 if (!context
->pixelFormat
) {
175 gl_err
= CGLCreateContext(context
->pixelFormat
,
176 shareContext
? shareContext
->ctx
: NULL
,
180 ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err
));
181 CGLDestroyPixelFormat(context
->pixelFormat
);
186 setup_dispatch_table();
187 GLAQUA_DEBUG_MSG("glAquaCreateContext done\n");
189 return &context
->base
;
192 /* maps from surface id -> list of __GLcontext */
193 static x_hash_table
*surface_hash
;
196 __glXAquaContextDestroy(__GLXcontext
*baseContext
)
200 __GLXAquaContext
*context
= (__GLXAquaContext
*)baseContext
;
202 GLAQUA_DEBUG_MSG("glAquaContextDestroy (ctx %p)\n", baseContext
);
203 if (context
!= NULL
) {
204 if (context
->sid
!= 0 && surface_hash
!= NULL
) {
206 x_hash_table_lookup(surface_hash
, x_cvt_uint_to_vptr(
207 context
->sid
), NULL
);
208 lst
= x_list_remove(lst
, context
);
209 x_hash_table_insert(surface_hash
, x_cvt_uint_to_vptr(
213 if (context
->ctx
!= NULL
)
214 CGLDestroyContext(context
->ctx
);
216 if (context
->pixelFormat
!= NULL
)
217 CGLDestroyPixelFormat(context
->pixelFormat
);
224 __glXAquaContextLoseCurrent(__GLXcontext
*baseContext
)
228 GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%p)\n", baseContext
);
230 gl_err
= CGLSetCurrentContext(NULL
);
232 ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err
));
235 * There should be no need to set __glXLastContext to NULL here, because
236 * glxcmds.c does it as part of the context cache flush after calling
243 /* Called when a surface is destroyed as a side effect of destroying
244 the window it's attached to. */
246 surface_notify(void *_arg
, void *data
)
248 DRISurfaceNotifyArg
*arg
= (DRISurfaceNotifyArg
*)_arg
;
249 __GLXAquaDrawable
*draw
= (__GLXAquaDrawable
*)data
;
250 __GLXAquaContext
*context
;
252 if (_arg
== NULL
|| data
== NULL
) {
253 ErrorF("surface_notify called with bad params");
257 GLAQUA_DEBUG_MSG("surface_notify(%p, %p)\n", _arg
, data
);
259 case AppleDRISurfaceNotifyDestroyed
:
260 if (surface_hash
!= NULL
)
261 x_hash_table_remove(surface_hash
, x_cvt_uint_to_vptr(arg
->id
));
266 case AppleDRISurfaceNotifyChanged
:
267 if (surface_hash
!= NULL
) {
269 x_hash_table_lookup(surface_hash
, x_cvt_uint_to_vptr(
271 for (; lst
!= NULL
; lst
= lst
->next
) {
273 xp_update_gl_context(context
->ctx
);
279 ErrorF("surface_notify: unknown kind %d\n", arg
->kind
);
285 attach(__GLXAquaContext
*context
, __GLXAquaDrawable
*draw
)
289 GLAQUA_DEBUG_MSG("attach(%p, %p)\n", context
, draw
);
291 if (NULL
== context
|| NULL
== draw
)
294 pDraw
= draw
->base
.pDraw
;
297 ErrorF("%s:%s() pDraw is NULL!\n", __FILE__
, __func__
);
301 if (draw
->sid
== 0) {
302 //if (!quartzProcs->CreateSurface(pDraw->pScreen, pDraw->id, pDraw,
303 if (!DRICreateSurface(pDraw
->pScreen
, pDraw
->id
, pDraw
,
305 surface_notify
, draw
))
310 if (!context
->isAttached
|| context
->sid
!= draw
->sid
) {
313 if (xp_attach_gl_context(context
->ctx
, draw
->sid
) != Success
) {
314 //quartzProcs->DestroySurface(pDraw->pScreen, pDraw->id, pDraw,
315 DRIDestroySurface(pDraw
->pScreen
, pDraw
->id
, pDraw
,
316 surface_notify
, draw
);
317 if (surface_hash
!= NULL
)
318 x_hash_table_remove(surface_hash
,
319 x_cvt_uint_to_vptr(draw
->sid
));
325 context
->isAttached
= TRUE
;
326 context
->sid
= draw
->sid
;
328 if (surface_hash
== NULL
)
329 surface_hash
= x_hash_table_new(NULL
, NULL
, NULL
, NULL
);
332 x_hash_table_lookup(surface_hash
, x_cvt_uint_to_vptr(
333 context
->sid
), NULL
);
334 if (x_list_find(lst
, context
) == NULL
) {
335 lst
= x_list_prepend(lst
, context
);
336 x_hash_table_insert(surface_hash
, x_cvt_uint_to_vptr(
340 GLAQUA_DEBUG_MSG("attached 0x%x to 0x%x\n", (unsigned int)pDraw
->id
,
341 (unsigned int)draw
->sid
);
344 draw
->context
= context
;
351 unattach(__GLXAquaContext
*context
)
354 GLAQUA_DEBUG_MSG("unattach\n");
355 if (context
== NULL
) {
356 ErrorF("Tried to unattach a null context\n");
359 if (context
->isAttached
) {
360 GLAQUA_DEBUG_MSG("unattaching\n");
362 if (surface_hash
!= NULL
) {
363 lst
= x_hash_table_lookup(surface_hash
, (void *)context
->sid
,
365 lst
= x_list_remove(lst
, context
);
366 x_hash_table_insert(surface_hash
, (void *)context
->sid
, lst
);
369 CGLClearDrawable(context
->ctx
);
370 context
->isAttached
= FALSE
;
377 __glXAquaContextMakeCurrent(__GLXcontext
*baseContext
)
380 __GLXAquaContext
*context
= (__GLXAquaContext
*)baseContext
;
381 __GLXAquaDrawable
*drawPriv
= (__GLXAquaDrawable
*)context
->base
.drawPriv
;
383 GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%p)\n", baseContext
);
385 if (attach(context
, drawPriv
))
388 gl_err
= CGLSetCurrentContext(context
->ctx
);
390 ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err
));
396 __glXAquaContextCopy(__GLXcontext
*baseDst
, __GLXcontext
*baseSrc
,
401 __GLXAquaContext
*dst
= (__GLXAquaContext
*)baseDst
;
402 __GLXAquaContext
*src
= (__GLXAquaContext
*)baseSrc
;
404 GLAQUA_DEBUG_MSG("GLXAquaContextCopy\n");
406 gl_err
= CGLCopyContext(src
->ctx
, dst
->ctx
, mask
);
408 ErrorF("CGLCopyContext error: %s\n", CGLErrorString(gl_err
));
413 /* Drawing surface notification callbacks */
415 __glXAquaDrawableSwapBuffers(ClientPtr client
, __GLXdrawable
*base
)
418 __GLXAquaDrawable
*drawable
;
420 // GLAQUA_DEBUG_MSG("glAquaDrawableSwapBuffers(%p)\n",base);
423 ErrorF("%s passed NULL\n", __func__
);
427 drawable
= (__GLXAquaDrawable
*)base
;
429 if (NULL
== drawable
->context
) {
430 ErrorF("%s called with a NULL->context for drawable %p!\n",
431 __func__
, (void *)drawable
);
435 err
= CGLFlushDrawable(drawable
->context
->ctx
);
437 if (kCGLNoError
!= err
) {
438 ErrorF("CGLFlushDrawable error: %s in %s\n", CGLErrorString(err
),
446 static CGLPixelFormatObj
447 makeFormat(__GLXconfig
*conf
)
449 CGLPixelFormatAttribute attr
[64];
450 CGLPixelFormatObj fobj
;
455 if (conf
->doubleBufferMode
)
456 attr
[i
++] = kCGLPFADoubleBuffer
;
458 if (conf
->stereoMode
)
459 attr
[i
++] = kCGLPFAStereo
;
461 attr
[i
++] = kCGLPFAColorSize
;
462 attr
[i
++] = conf
->redBits
+ conf
->greenBits
+ conf
->blueBits
;
463 attr
[i
++] = kCGLPFAAlphaSize
;
464 attr
[i
++] = conf
->alphaBits
;
466 if ((conf
->accumRedBits
+ conf
->accumGreenBits
+ conf
->accumBlueBits
+
467 conf
->accumAlphaBits
) > 0) {
469 attr
[i
++] = kCGLPFAAccumSize
;
470 attr
[i
++] = conf
->accumRedBits
+ conf
->accumGreenBits
471 + conf
->accumBlueBits
+ conf
->accumAlphaBits
;
474 attr
[i
++] = kCGLPFADepthSize
;
475 attr
[i
++] = conf
->depthBits
;
477 if (conf
->stencilBits
) {
478 attr
[i
++] = kCGLPFAStencilSize
;
479 attr
[i
++] = conf
->stencilBits
;
482 if (conf
->numAuxBuffers
> 0) {
483 attr
[i
++] = kCGLPFAAuxBuffers
;
484 attr
[i
++] = conf
->numAuxBuffers
;
487 if (conf
->sampleBuffers
> 0) {
488 attr
[i
++] = kCGLPFASampleBuffers
;
489 attr
[i
++] = conf
->sampleBuffers
;
490 attr
[i
++] = kCGLPFASamples
;
491 attr
[i
++] = conf
->samples
;
496 error
= CGLChoosePixelFormat(attr
, &fobj
, &formats
);
498 ErrorF("error: creating pixel format %s\n", CGLErrorString(error
));
506 __glXAquaScreenDestroy(__GLXscreen
*screen
)
509 GLAQUA_DEBUG_MSG("glXAquaScreenDestroy(%p)\n", screen
);
510 __glXScreenDestroy(screen
);
515 /* This is called by __glXInitScreens(). */
517 __glXAquaScreenProbe(ScreenPtr pScreen
)
519 __GLXAquaScreen
*screen
;
521 GLAQUA_DEBUG_MSG("glXAquaScreenProbe\n");
526 screen
= calloc(1, sizeof *screen
);
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
;
537 screen
->base
.fbconfigs
= __glXAquaCreateVisualConfigs(
538 &screen
->base
.numFBConfigs
, pScreen
->myNum
);
540 __glXScreenInit(&screen
->base
, pScreen
);
542 screen
->base
.GLXmajor
= 1;
543 screen
->base
.GLXminor
= 4;
544 screen
->base
.GLXextensions
= strdup("GLX_SGIX_fbconfig "
545 "GLX_SGIS_multisample "
546 "GLX_ARB_multisample "
547 "GLX_EXT_visual_info "
548 "GLX_EXT_import_context ");
550 /*We may be able to add more GLXextensions at a later time. */
552 return &screen
->base
;
557 __glXAquaDrawableCopySubBuffer(__GLXdrawable
*drawable
,
558 int x
, int y
, int w
, int h
)
565 __glXAquaDrawableDestroy(__GLXdrawable
*base
)
567 /* gstaplin: base is the head of the structure, so it's at the same
569 * Is this safe with strict aliasing? I noticed that the other dri code
572 __GLXAquaDrawable
*glxPriv
= (__GLXAquaDrawable
*)base
;
574 GLAQUA_DEBUG_MSG("TRACE");
576 /* It doesn't work to call DRIDestroySurface here, the drawable's
577 already gone.. But dri.c notices the window destruction and
578 frees the surface itself. */
580 /*gstaplin: verify the statement above. The surface destroy
581 *messages weren't making it through, and may still not be.
582 *We need a good test case for surface creation and destruction.
583 *We also need a good way to enable introspection on the server
584 *to validate the test, beyond using gdb with print.
590 static __GLXdrawable
*
591 __glXAquaScreenCreateDrawable(ClientPtr client
,
599 __GLXAquaDrawable
*glxPriv
;
601 glxPriv
= malloc(sizeof *glxPriv
);
606 memset(glxPriv
, 0, sizeof *glxPriv
);
608 if (!__glXDrawableInit(&glxPriv
->base
, screen
, pDraw
, type
, glxDrawId
,
614 glxPriv
->base
.destroy
= __glXAquaDrawableDestroy
;
615 glxPriv
->base
.swapBuffers
= __glXAquaDrawableSwapBuffers
;
616 glxPriv
->base
.copySubBuffer
= NULL
; /* __glXAquaDrawableCopySubBuffer; */
618 glxPriv
->pDraw
= pDraw
;
620 glxPriv
->context
= NULL
;
622 return &glxPriv
->base
;
625 // Extra goodies for glx
628 __glFloorLog2(GLuint val
)
639 #ifndef OPENGL_FRAMEWORK_PATH
640 #define OPENGL_FRAMEWORK_PATH \
641 "/System/Library/Frameworks/OpenGL.framework/OpenGL"
644 static void *opengl_framework_handle
;
647 get_proc_address(const char *sym
)
649 return (glx_func_ptr
) dlsym(opengl_framework_handle
, sym
);
653 setup_dispatch_table(void)
655 const char *opengl_framework_path
;
657 if (opengl_framework_handle
) {
661 opengl_framework_path
= getenv("OPENGL_FRAMEWORK_PATH");
662 if (!opengl_framework_path
) {
663 opengl_framework_path
= OPENGL_FRAMEWORK_PATH
;
666 (void)dlerror(); /*drain dlerror */
667 opengl_framework_handle
= dlopen(opengl_framework_path
, RTLD_LOCAL
);
669 if (!opengl_framework_handle
) {
670 ErrorF("unable to dlopen %s : %s, using RTLD_DEFAULT\n",
671 opengl_framework_path
, dlerror());
672 opengl_framework_handle
= RTLD_DEFAULT
;
675 __glXsetGetProcAddress(get_proc_address
);