xref: /OK3568_Linux_fs/external/xserver/hw/xquartz/GL/indirect.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 *
__glXAquaScreenCreateContext(__GLXscreen * screen,__GLXconfig * conf,__GLXcontext * baseShareContext,unsigned num_attribs,const uint32_t * attribs,int * error)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
__glXAquaContextDestroy(__GLXcontext * baseContext)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
__glXAquaContextLoseCurrent(__GLXcontext * baseContext)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
surface_notify(void * _arg,void * data)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
attach(__GLXAquaContext * context,__GLXAquaDrawable * draw)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
__glXAquaContextMakeCurrent(__GLXcontext * baseContext)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
__glXAquaContextCopy(__GLXcontext * baseDst,__GLXcontext * baseSrc,unsigned long mask)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
__glXAquaDrawableSwapBuffers(ClientPtr client,__GLXdrawable * base)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
makeFormat(__GLXconfig * conf)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
__glXAquaScreenDestroy(__GLXscreen * screen)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 *
__glXAquaScreenProbe(ScreenPtr pScreen)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
__glXAquaDrawableDestroy(__GLXdrawable * base)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 *
__glXAquaScreenCreateDrawable(ClientPtr client,__GLXscreen * screen,DrawablePtr pDraw,XID drawId,int type,XID glxDrawId,__GLXconfig * conf)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
__glFloorLog2(GLuint val)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
get_proc_address(const char * sym)638 get_proc_address(const char *sym)
639 {
640     return (glx_func_ptr) dlsym(opengl_framework_handle, sym);
641 }
642 
643 static void
setup_dispatch_table(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 }
668