Commit | Line | Data |
---|---|---|
a09e091a JB |
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 <AvailabilityMacros.h> | |
39 | ||
40 | #include <dlfcn.h> | |
41 | ||
42 | #include <OpenGL/OpenGL.h> | |
43 | #include <OpenGL/gl.h> /* Just to prevent glxserver.h from loading mesa's and colliding with OpenGL.h */ | |
44 | ||
45 | #include <X11/Xproto.h> | |
46 | #include <GL/glxproto.h> | |
47 | ||
48 | #include <glxserver.h> | |
49 | #include <glxutil.h> | |
50 | ||
51 | #include "x-hash.h" | |
52 | ||
53 | #include "visualConfigs.h" | |
54 | #include "dri.h" | |
55 | ||
56 | #include "darwin.h" | |
57 | #define GLAQUA_DEBUG_MSG(msg, args ...) ASL_LOG(ASL_LEVEL_DEBUG, "GLXAqua", \ | |
58 | msg, \ | |
59 | ## args) | |
60 | ||
61 | __GLXprovider * | |
62 | GlxGetDRISWrastProvider(void); | |
63 | ||
64 | static void | |
65 | setup_dispatch_table(void); | |
66 | GLuint | |
67 | __glFloorLog2(GLuint val); | |
68 | void | |
69 | warn_func(void * p1, char *format, ...); | |
70 | ||
71 | // some prototypes | |
72 | static __GLXscreen * | |
73 | __glXAquaScreenProbe(ScreenPtr pScreen); | |
74 | static __GLXdrawable * | |
75 | __glXAquaScreenCreateDrawable(ClientPtr client, __GLXscreen *screen, | |
76 | DrawablePtr pDraw, XID drawId, int type, | |
77 | XID glxDrawId, | |
78 | __GLXconfig *conf); | |
79 | ||
80 | static void | |
81 | __glXAquaContextDestroy(__GLXcontext *baseContext); | |
82 | static int | |
83 | __glXAquaContextMakeCurrent(__GLXcontext *baseContext); | |
84 | static int | |
85 | __glXAquaContextLoseCurrent(__GLXcontext *baseContext); | |
86 | static int | |
87 | __glXAquaContextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, | |
88 | unsigned long mask); | |
89 | ||
90 | static CGLPixelFormatObj | |
91 | makeFormat(__GLXconfig *conf); | |
92 | ||
93 | __GLXprovider __glXDRISWRastProvider = { | |
94 | __glXAquaScreenProbe, | |
95 | "Core OpenGL", | |
96 | NULL | |
97 | }; | |
98 | ||
99 | typedef struct __GLXAquaScreen __GLXAquaScreen; | |
100 | typedef struct __GLXAquaContext __GLXAquaContext; | |
101 | typedef struct __GLXAquaDrawable __GLXAquaDrawable; | |
102 | ||
103 | /* | |
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 | |
106 | * in GLX. | |
107 | * | |
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. | |
111 | */ | |
112 | struct __GLXAquaScreen { | |
113 | __GLXscreen base; | |
114 | int index; | |
115 | int num_vis; | |
116 | }; | |
117 | ||
118 | struct __GLXAquaContext { | |
119 | __GLXcontext base; | |
120 | CGLContextObj ctx; | |
121 | CGLPixelFormatObj pixelFormat; | |
122 | xp_surface_id sid; | |
123 | unsigned isAttached : 1; | |
124 | }; | |
125 | ||
126 | struct __GLXAquaDrawable { | |
127 | __GLXdrawable base; | |
128 | DrawablePtr pDraw; | |
129 | xp_surface_id sid; | |
130 | __GLXAquaContext *context; | |
131 | }; | |
132 | ||
133 | static __GLXcontext * | |
134 | __glXAquaScreenCreateContext(__GLXscreen *screen, | |
135 | __GLXconfig *conf, | |
136 | __GLXcontext *baseShareContext, | |
137 | unsigned num_attribs, | |
138 | const uint32_t *attribs, | |
139 | int *error) | |
140 | { | |
141 | __GLXAquaContext *context; | |
142 | __GLXAquaContext *shareContext = (__GLXAquaContext *)baseShareContext; | |
143 | CGLError gl_err; | |
144 | ||
145 | /* Unused (for now?) */ | |
146 | (void)num_attribs; | |
147 | (void)attribs; | |
148 | (void)error; | |
149 | ||
150 | GLAQUA_DEBUG_MSG("glXAquaScreenCreateContext\n"); | |
151 | ||
152 | context = calloc(1, sizeof(__GLXAquaContext)); | |
153 | ||
154 | if (context == NULL) | |
155 | return NULL; | |
156 | ||
157 | memset(context, 0, sizeof *context); | |
158 | ||
159 | context->base.pGlxScreen = screen; | |
160 | ||
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. */ | |
166 | ||
167 | context->pixelFormat = makeFormat(conf); | |
168 | ||
169 | if (!context->pixelFormat) { | |
170 | free(context); | |
171 | return NULL; | |
172 | } | |
173 | ||
174 | context->ctx = NULL; | |
175 | gl_err = CGLCreateContext(context->pixelFormat, | |
176 | shareContext ? shareContext->ctx : NULL, | |
177 | &context->ctx); | |
178 | ||
179 | if (gl_err != 0) { | |
180 | ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err)); | |
181 | CGLDestroyPixelFormat(context->pixelFormat); | |
182 | free(context); | |
183 | return NULL; | |
184 | } | |
185 | ||
186 | setup_dispatch_table(); | |
187 | GLAQUA_DEBUG_MSG("glAquaCreateContext done\n"); | |
188 | ||
189 | return &context->base; | |
190 | } | |
191 | ||
192 | /* maps from surface id -> list of __GLcontext */ | |
193 | static x_hash_table *surface_hash; | |
194 | ||
195 | static void | |
196 | __glXAquaContextDestroy(__GLXcontext *baseContext) | |
197 | { | |
198 | x_list *lst; | |
199 | ||
200 | __GLXAquaContext *context = (__GLXAquaContext *)baseContext; | |
201 | ||
202 | GLAQUA_DEBUG_MSG("glAquaContextDestroy (ctx %p)\n", baseContext); | |
203 | if (context != NULL) { | |
204 | if (context->sid != 0 && surface_hash != NULL) { | |
205 | lst = | |
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( | |
210 | context->sid), lst); | |
211 | } | |
212 | ||
213 | if (context->ctx != NULL) | |
214 | CGLDestroyContext(context->ctx); | |
215 | ||
216 | if (context->pixelFormat != NULL) | |
217 | CGLDestroyPixelFormat(context->pixelFormat); | |
218 | ||
219 | free(context); | |
220 | } | |
221 | } | |
222 | ||
223 | static int | |
224 | __glXAquaContextLoseCurrent(__GLXcontext *baseContext) | |
225 | { | |
226 | CGLError gl_err; | |
227 | ||
228 | GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%p)\n", baseContext); | |
229 | ||
230 | gl_err = CGLSetCurrentContext(NULL); | |
231 | if (gl_err != 0) | |
232 | ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); | |
233 | ||
234 | /* | |
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 | |
237 | * this. | |
238 | */ | |
239 | ||
240 | return GL_TRUE; | |
241 | } | |
242 | ||
243 | /* Called when a surface is destroyed as a side effect of destroying | |
244 | the window it's attached to. */ | |
245 | static void | |
246 | surface_notify(void *_arg, void *data) | |
247 | { | |
248 | DRISurfaceNotifyArg *arg = (DRISurfaceNotifyArg *)_arg; | |
249 | __GLXAquaDrawable *draw = (__GLXAquaDrawable *)data; | |
250 | __GLXAquaContext *context; | |
251 | x_list *lst; | |
252 | if (_arg == NULL || data == NULL) { | |
253 | ErrorF("surface_notify called with bad params"); | |
254 | return; | |
255 | } | |
256 | ||
257 | GLAQUA_DEBUG_MSG("surface_notify(%p, %p)\n", _arg, data); | |
258 | switch (arg->kind) { | |
259 | case AppleDRISurfaceNotifyDestroyed: | |
260 | if (surface_hash != NULL) | |
261 | x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(arg->id)); | |
262 | draw->pDraw = NULL; | |
263 | draw->sid = 0; | |
264 | break; | |
265 | ||
266 | case AppleDRISurfaceNotifyChanged: | |
267 | if (surface_hash != NULL) { | |
268 | lst = | |
269 | x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr( | |
270 | arg->id), NULL); | |
271 | for (; lst != NULL; lst = lst->next) { | |
272 | context = lst->data; | |
273 | xp_update_gl_context(context->ctx); | |
274 | } | |
275 | } | |
276 | break; | |
277 | ||
278 | default: | |
279 | ErrorF("surface_notify: unknown kind %d\n", arg->kind); | |
280 | break; | |
281 | } | |
282 | } | |
283 | ||
284 | static BOOL | |
285 | attach(__GLXAquaContext *context, __GLXAquaDrawable *draw) | |
286 | { | |
287 | DrawablePtr pDraw; | |
288 | ||
289 | GLAQUA_DEBUG_MSG("attach(%p, %p)\n", context, draw); | |
290 | ||
291 | if (NULL == context || NULL == draw) | |
292 | return TRUE; | |
293 | ||
294 | pDraw = draw->base.pDraw; | |
295 | ||
296 | if (NULL == pDraw) { | |
297 | ErrorF("%s:%s() pDraw is NULL!\n", __FILE__, __func__); | |
298 | return TRUE; | |
299 | } | |
300 | ||
301 | if (draw->sid == 0) { | |
302 | //if (!quartzProcs->CreateSurface(pDraw->pScreen, pDraw->id, pDraw, | |
303 | if (!DRICreateSurface(pDraw->pScreen, pDraw->id, pDraw, | |
304 | 0, &draw->sid, NULL, | |
305 | surface_notify, draw)) | |
306 | return TRUE; | |
307 | draw->pDraw = pDraw; | |
308 | } | |
309 | ||
310 | if (!context->isAttached || context->sid != draw->sid) { | |
311 | x_list *lst; | |
312 | ||
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)); | |
320 | ||
321 | draw->sid = 0; | |
322 | return TRUE; | |
323 | } | |
324 | ||
325 | context->isAttached = TRUE; | |
326 | context->sid = draw->sid; | |
327 | ||
328 | if (surface_hash == NULL) | |
329 | surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL); | |
330 | ||
331 | lst = | |
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( | |
337 | context->sid), lst); | |
338 | } | |
339 | ||
340 | GLAQUA_DEBUG_MSG("attached 0x%x to 0x%x\n", (unsigned int)pDraw->id, | |
341 | (unsigned int)draw->sid); | |
342 | } | |
343 | ||
344 | draw->context = context; | |
345 | ||
346 | return FALSE; | |
347 | } | |
348 | ||
349 | #if 0 // unused | |
350 | static void | |
351 | unattach(__GLXAquaContext *context) | |
352 | { | |
353 | x_list *lst; | |
354 | GLAQUA_DEBUG_MSG("unattach\n"); | |
355 | if (context == NULL) { | |
356 | ErrorF("Tried to unattach a null context\n"); | |
357 | return; | |
358 | } | |
359 | if (context->isAttached) { | |
360 | GLAQUA_DEBUG_MSG("unattaching\n"); | |
361 | ||
362 | if (surface_hash != NULL) { | |
363 | lst = x_hash_table_lookup(surface_hash, (void *)context->sid, | |
364 | NULL); | |
365 | lst = x_list_remove(lst, context); | |
366 | x_hash_table_insert(surface_hash, (void *)context->sid, lst); | |
367 | } | |
368 | ||
369 | CGLClearDrawable(context->ctx); | |
370 | context->isAttached = FALSE; | |
371 | context->sid = 0; | |
372 | } | |
373 | } | |
374 | #endif | |
375 | ||
376 | static int | |
377 | __glXAquaContextMakeCurrent(__GLXcontext *baseContext) | |
378 | { | |
379 | CGLError gl_err; | |
380 | __GLXAquaContext *context = (__GLXAquaContext *)baseContext; | |
381 | __GLXAquaDrawable *drawPriv = (__GLXAquaDrawable *)context->base.drawPriv; | |
382 | ||
383 | GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%p)\n", baseContext); | |
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 | __glXScreenInit(&screen->base, pScreen); | |
541 | ||
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 "); | |
549 | ||
550 | /*We may be able to add more GLXextensions at a later time. */ | |
551 | ||
552 | return &screen->base; | |
553 | } | |
554 | ||
555 | #if 0 // unused | |
556 | static void | |
557 | __glXAquaDrawableCopySubBuffer(__GLXdrawable *drawable, | |
558 | int x, int y, int w, int h) | |
559 | { | |
560 | /*TODO finish me*/ | |
561 | } | |
562 | #endif | |
563 | ||
564 | static void | |
565 | __glXAquaDrawableDestroy(__GLXdrawable *base) | |
566 | { | |
567 | /* gstaplin: base is the head of the structure, so it's at the same | |
568 | * offset in memory. | |
569 | * Is this safe with strict aliasing? I noticed that the other dri code | |
570 | * does this too... | |
571 | */ | |
572 | __GLXAquaDrawable *glxPriv = (__GLXAquaDrawable *)base; | |
573 | ||
574 | GLAQUA_DEBUG_MSG("TRACE"); | |
575 | ||
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. */ | |
579 | ||
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. | |
585 | */ | |
586 | ||
587 | free(glxPriv); | |
588 | } | |
589 | ||
590 | static __GLXdrawable * | |
591 | __glXAquaScreenCreateDrawable(ClientPtr client, | |
592 | __GLXscreen *screen, | |
593 | DrawablePtr pDraw, | |
594 | XID drawId, | |
595 | int type, | |
596 | XID glxDrawId, | |
597 | __GLXconfig *conf) | |
598 | { | |
599 | __GLXAquaDrawable *glxPriv; | |
600 | ||
601 | glxPriv = malloc(sizeof *glxPriv); | |
602 | ||
603 | if (glxPriv == NULL) | |
604 | return NULL; | |
605 | ||
606 | memset(glxPriv, 0, sizeof *glxPriv); | |
607 | ||
608 | if (!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, glxDrawId, | |
609 | conf)) { | |
610 | free(glxPriv); | |
611 | return NULL; | |
612 | } | |
613 | ||
614 | glxPriv->base.destroy = __glXAquaDrawableDestroy; | |
615 | glxPriv->base.swapBuffers = __glXAquaDrawableSwapBuffers; | |
616 | glxPriv->base.copySubBuffer = NULL; /* __glXAquaDrawableCopySubBuffer; */ | |
617 | ||
618 | glxPriv->pDraw = pDraw; | |
619 | glxPriv->sid = 0; | |
620 | glxPriv->context = NULL; | |
621 | ||
622 | return &glxPriv->base; | |
623 | } | |
624 | ||
625 | // Extra goodies for glx | |
626 | ||
627 | GLuint | |
628 | __glFloorLog2(GLuint val) | |
629 | { | |
630 | int c = 0; | |
631 | ||
632 | while (val > 1) { | |
633 | c++; | |
634 | val >>= 1; | |
635 | } | |
636 | return c; | |
637 | } | |
638 | ||
639 | #ifndef OPENGL_FRAMEWORK_PATH | |
640 | #define OPENGL_FRAMEWORK_PATH \ | |
641 | "/System/Library/Frameworks/OpenGL.framework/OpenGL" | |
642 | #endif | |
643 | ||
644 | static void *opengl_framework_handle; | |
645 | ||
646 | static glx_func_ptr | |
647 | get_proc_address(const char *sym) | |
648 | { | |
649 | return (glx_func_ptr) dlsym(opengl_framework_handle, sym); | |
650 | } | |
651 | ||
652 | static void | |
653 | setup_dispatch_table(void) | |
654 | { | |
655 | const char *opengl_framework_path; | |
656 | ||
657 | if (opengl_framework_handle) { | |
658 | return; | |
659 | } | |
660 | ||
661 | opengl_framework_path = getenv("OPENGL_FRAMEWORK_PATH"); | |
662 | if (!opengl_framework_path) { | |
663 | opengl_framework_path = OPENGL_FRAMEWORK_PATH; | |
664 | } | |
665 | ||
666 | (void)dlerror(); /*drain dlerror */ | |
667 | opengl_framework_handle = dlopen(opengl_framework_path, RTLD_LOCAL); | |
668 | ||
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; | |
673 | } | |
674 | ||
675 | __glXsetGetProcAddress(get_proc_address); | |
676 | } |