1706f2543Smrg/*
2706f2543Smrg * GLX implementation that uses Apple's OpenGL.framework
3706f2543Smrg * (Indirect rendering path -- it's also used for some direct mode code too)
4706f2543Smrg *
5706f2543Smrg * Copyright (c) 2007-2011 Apple Inc.
6706f2543Smrg * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved.
7706f2543Smrg * Copyright (c) 2002 Greg Parker. All Rights Reserved.
8706f2543Smrg *
9706f2543Smrg * Portions of this file are copied from Mesa's xf86glx.c,
10706f2543Smrg * which contains the following copyright:
11706f2543Smrg *
12706f2543Smrg * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
13706f2543Smrg * All Rights Reserved.
14706f2543Smrg *
15706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
16706f2543Smrg * copy of this software and associated documentation files (the "Software"),
17706f2543Smrg * to deal in the Software without restriction, including without limitation
18706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
20706f2543Smrg * Software is furnished to do so, subject to the following conditions:
21706f2543Smrg *
22706f2543Smrg * The above copyright notice and this permission notice shall be included in
23706f2543Smrg * all copies or substantial portions of the Software.
24706f2543Smrg *
25706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
29706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31706f2543Smrg * DEALINGS IN THE SOFTWARE.
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
35706f2543Smrg#include <dix-config.h>
36706f2543Smrg#endif
37706f2543Smrg
38706f2543Smrg#include <AvailabilityMacros.h>
39706f2543Smrg
40706f2543Smrg#include <dlfcn.h>
41706f2543Smrg
42706f2543Smrg#include <OpenGL/OpenGL.h>
43706f2543Smrg#include <OpenGL/gl.h>     /* Just to prevent glxserver.h from loading mesa's and colliding with OpenGL.h */
44706f2543Smrg
45706f2543Smrg#include <X11/Xproto.h>
46706f2543Smrg#include <GL/glxproto.h>
47706f2543Smrg
48706f2543Smrg#include <glxserver.h>
49706f2543Smrg#include <glxutil.h>
50706f2543Smrg
51706f2543Smrgtypedef unsigned long long GLuint64EXT;
52706f2543Smrgtypedef long long GLint64EXT;
53706f2543Smrg#include <dispatch.h>
54706f2543Smrg#include <glapi.h>
55706f2543Smrg
56706f2543Smrg#include "x-hash.h"
57706f2543Smrg
58706f2543Smrg#include "visualConfigs.h"
59706f2543Smrg#include "dri.h"
60706f2543Smrg
61706f2543Smrg// Write debugging output, or not
62706f2543Smrg#ifdef GLAQUA_DEBUG
63706f2543Smrg#define GLAQUA_DEBUG_MSG ErrorF
64706f2543Smrg#else
65706f2543Smrg#define GLAQUA_DEBUG_MSG(a, ...)
66706f2543Smrg#endif
67706f2543Smrg
68706f2543Smrg__GLXprovider * GlxGetDRISWrastProvider (void);
69706f2543Smrg
70706f2543Smrgstatic void setup_dispatch_table(void);
71706f2543SmrgGLuint __glFloorLog2(GLuint val);
72706f2543Smrgvoid warn_func(void * p1, char *format, ...);
73706f2543Smrg
74706f2543Smrg// some prototypes
75706f2543Smrgstatic __GLXscreen * __glXAquaScreenProbe(ScreenPtr pScreen);
76706f2543Smrgstatic __GLXdrawable * __glXAquaScreenCreateDrawable(ClientPtr client, __GLXscreen *screen, DrawablePtr pDraw, XID drawId, int type, XID glxDrawId, __GLXconfig *conf);
77706f2543Smrg
78706f2543Smrgstatic void __glXAquaContextDestroy(__GLXcontext *baseContext);
79706f2543Smrgstatic int __glXAquaContextMakeCurrent(__GLXcontext *baseContext);
80706f2543Smrgstatic int __glXAquaContextLoseCurrent(__GLXcontext *baseContext);
81706f2543Smrgstatic int __glXAquaContextForceCurrent(__GLXcontext *baseContext);
82706f2543Smrgstatic int __glXAquaContextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, unsigned long mask);
83706f2543Smrg
84706f2543Smrgstatic CGLPixelFormatObj makeFormat(__GLXconfig *conf);
85706f2543Smrg
86706f2543Smrg__GLXprovider __glXDRISWRastProvider = {
87706f2543Smrg    __glXAquaScreenProbe,
88706f2543Smrg    "Core OpenGL",
89706f2543Smrg    NULL
90706f2543Smrg};
91706f2543Smrg
92706f2543Smrgtypedef struct __GLXAquaScreen   __GLXAquaScreen;
93706f2543Smrgtypedef struct __GLXAquaContext  __GLXAquaContext;
94706f2543Smrgtypedef struct __GLXAquaDrawable __GLXAquaDrawable;
95706f2543Smrg
96706f2543Smrg/*
97706f2543Smrg * The following structs must keep the base as the first member.
98706f2543Smrg * It's used to treat the start of the struct as a different struct
99706f2543Smrg * in GLX.
100706f2543Smrg *
101706f2543Smrg * Note: these structs should be initialized with xcalloc or memset
102706f2543Smrg * prior to usage, and some of them require initializing
103706f2543Smrg * the base with function pointers.
104706f2543Smrg */
105706f2543Smrgstruct __GLXAquaScreen {
106706f2543Smrg    __GLXscreen base;
107706f2543Smrg    int index;
108706f2543Smrg    int num_vis;
109706f2543Smrg};
110706f2543Smrg
111706f2543Smrgstruct __GLXAquaContext {
112706f2543Smrg    __GLXcontext base;
113706f2543Smrg    CGLContextObj ctx;
114706f2543Smrg    CGLPixelFormatObj pixelFormat;
115706f2543Smrg    xp_surface_id sid;
116706f2543Smrg    unsigned isAttached :1;
117706f2543Smrg};
118706f2543Smrg
119706f2543Smrgstruct __GLXAquaDrawable {
120706f2543Smrg    __GLXdrawable base;
121706f2543Smrg    DrawablePtr pDraw;
122706f2543Smrg    xp_surface_id sid;
123706f2543Smrg    __GLXAquaContext *context;
124706f2543Smrg};
125706f2543Smrg
126706f2543Smrg
127706f2543Smrgstatic __GLXcontext *
128706f2543Smrg__glXAquaScreenCreateContext(__GLXscreen *screen,
129706f2543Smrg			     __GLXconfig *conf,
130706f2543Smrg			     __GLXcontext *baseShareContext)
131706f2543Smrg{
132706f2543Smrg    __GLXAquaContext *context;
133706f2543Smrg    __GLXAquaContext *shareContext = (__GLXAquaContext *) baseShareContext;
134706f2543Smrg    CGLError gl_err;
135706f2543Smrg
136706f2543Smrg    GLAQUA_DEBUG_MSG("glXAquaScreenCreateContext\n");
137706f2543Smrg
138706f2543Smrg    context = calloc(1, sizeof (__GLXAquaContext));
139706f2543Smrg
140706f2543Smrg    if (context == NULL)
141706f2543Smrg	return NULL;
142706f2543Smrg
143706f2543Smrg    memset(context, 0, sizeof *context);
144706f2543Smrg
145706f2543Smrg    context->base.pGlxScreen = screen;
146706f2543Smrg
147706f2543Smrg    context->base.destroy        = __glXAquaContextDestroy;
148706f2543Smrg    context->base.makeCurrent    = __glXAquaContextMakeCurrent;
149706f2543Smrg    context->base.loseCurrent    = __glXAquaContextLoseCurrent;
150706f2543Smrg    context->base.copy           = __glXAquaContextCopy;
151706f2543Smrg    context->base.forceCurrent   = __glXAquaContextForceCurrent;
152706f2543Smrg    /*FIXME verify that the context->base is fully initialized. */
153706f2543Smrg
154706f2543Smrg    context->pixelFormat = makeFormat(conf);
155706f2543Smrg
156706f2543Smrg    if (!context->pixelFormat) {
157706f2543Smrg        free(context);
158706f2543Smrg        return NULL;
159706f2543Smrg    }
160706f2543Smrg
161706f2543Smrg    context->ctx = NULL;
162706f2543Smrg    gl_err = CGLCreateContext(context->pixelFormat,
163706f2543Smrg			      shareContext ? shareContext->ctx : NULL,
164706f2543Smrg			      &context->ctx);
165706f2543Smrg
166706f2543Smrg    if (gl_err != 0) {
167706f2543Smrg	ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err));
168706f2543Smrg	CGLDestroyPixelFormat(context->pixelFormat);
169706f2543Smrg	free(context);
170706f2543Smrg	return NULL;
171706f2543Smrg    }
172706f2543Smrg
173706f2543Smrg    setup_dispatch_table();
174706f2543Smrg    GLAQUA_DEBUG_MSG("glAquaCreateContext done\n");
175706f2543Smrg
176706f2543Smrg    return &context->base;
177706f2543Smrg}
178706f2543Smrg
179706f2543Smrg/* maps from surface id -> list of __GLcontext */
180706f2543Smrgstatic x_hash_table *surface_hash;
181706f2543Smrg
182706f2543Smrgstatic void __glXAquaContextDestroy(__GLXcontext *baseContext) {
183706f2543Smrg    x_list *lst;
184706f2543Smrg
185706f2543Smrg    __GLXAquaContext *context = (__GLXAquaContext *) baseContext;
186706f2543Smrg
187706f2543Smrg    GLAQUA_DEBUG_MSG("glAquaContextDestroy (ctx %p)\n", baseContext);
188706f2543Smrg    if (context != NULL) {
189706f2543Smrg      if (context->sid != 0 && surface_hash != NULL) {
190706f2543Smrg		lst = x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr(context->sid), NULL);
191706f2543Smrg		lst = x_list_remove(lst, context);
192706f2543Smrg		x_hash_table_insert(surface_hash, x_cvt_uint_to_vptr(context->sid), lst);
193706f2543Smrg      }
194706f2543Smrg
195706f2543Smrg      if (context->ctx != NULL)
196706f2543Smrg	  CGLDestroyContext(context->ctx);
197706f2543Smrg
198706f2543Smrg      if (context->pixelFormat != NULL)
199706f2543Smrg	  CGLDestroyPixelFormat(context->pixelFormat);
200706f2543Smrg
201706f2543Smrg      free(context);
202706f2543Smrg    }
203706f2543Smrg}
204706f2543Smrg
205706f2543Smrgstatic int __glXAquaContextLoseCurrent(__GLXcontext *baseContext) {
206706f2543Smrg    CGLError gl_err;
207706f2543Smrg
208706f2543Smrg    GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%p)\n", baseContext);
209706f2543Smrg
210706f2543Smrg    gl_err = CGLSetCurrentContext(NULL);
211706f2543Smrg    if (gl_err != 0)
212706f2543Smrg      ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err));
213706f2543Smrg
214706f2543Smrg    /*
215706f2543Smrg     * There should be no need to set __glXLastContext to NULL here, because
216706f2543Smrg     * glxcmds.c does it as part of the context cache flush after calling
217706f2543Smrg     * this.
218706f2543Smrg     */
219706f2543Smrg
220706f2543Smrg    return GL_TRUE;
221706f2543Smrg}
222706f2543Smrg
223706f2543Smrg/* Called when a surface is destroyed as a side effect of destroying
224706f2543Smrg   the window it's attached to. */
225706f2543Smrgstatic void surface_notify(void *_arg, void *data) {
226706f2543Smrg    DRISurfaceNotifyArg *arg = (DRISurfaceNotifyArg *)_arg;
227706f2543Smrg    __GLXAquaDrawable *draw = (__GLXAquaDrawable *)data;
228706f2543Smrg    __GLXAquaContext *context;
229706f2543Smrg    x_list *lst;
230706f2543Smrg    if(_arg == NULL || data == NULL) {
231706f2543Smrg	    ErrorF("surface_notify called with bad params");
232706f2543Smrg	    return;
233706f2543Smrg    }
234706f2543Smrg
235706f2543Smrg    GLAQUA_DEBUG_MSG("surface_notify(%p, %p)\n", _arg, data);
236706f2543Smrg    switch (arg->kind) {
237706f2543Smrg    case AppleDRISurfaceNotifyDestroyed:
238706f2543Smrg        if (surface_hash != NULL)
239706f2543Smrg            x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(arg->id));
240706f2543Smrg	draw->pDraw = NULL;
241706f2543Smrg	draw->sid = 0;
242706f2543Smrg        break;
243706f2543Smrg
244706f2543Smrg    case AppleDRISurfaceNotifyChanged:
245706f2543Smrg        if (surface_hash != NULL) {
246706f2543Smrg            lst = x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr(arg->id), NULL);
247706f2543Smrg            for (; lst != NULL; lst = lst->next)
248706f2543Smrg		{
249706f2543Smrg                context = lst->data;
250706f2543Smrg                xp_update_gl_context(context->ctx);
251706f2543Smrg            }
252706f2543Smrg        }
253706f2543Smrg        break;
254706f2543Smrg    default:
255706f2543Smrg	ErrorF("surface_notify: unknown kind %d\n", arg->kind);
256706f2543Smrg	break;
257706f2543Smrg    }
258706f2543Smrg}
259706f2543Smrg
260706f2543Smrgstatic BOOL attach(__GLXAquaContext *context, __GLXAquaDrawable *draw) {
261706f2543Smrg    DrawablePtr pDraw;
262706f2543Smrg
263706f2543Smrg    GLAQUA_DEBUG_MSG("attach(%p, %p)\n", context, draw);
264706f2543Smrg
265706f2543Smrg    if(NULL == context || NULL == draw)
266706f2543Smrg	return TRUE;
267706f2543Smrg
268706f2543Smrg    pDraw = draw->base.pDraw;
269706f2543Smrg
270706f2543Smrg    if(NULL == pDraw) {
271706f2543Smrg	ErrorF("%s:%s() pDraw is NULL!\n", __FILE__, __func__);
272706f2543Smrg	return TRUE;
273706f2543Smrg    }
274706f2543Smrg
275706f2543Smrg    if (draw->sid == 0) {
276706f2543Smrg	//if (!quartzProcs->CreateSurface(pDraw->pScreen, pDraw->id, pDraw,
277706f2543Smrg        if (!DRICreateSurface(pDraw->pScreen, pDraw->id, pDraw,
278706f2543Smrg			      0, &draw->sid, NULL,
279706f2543Smrg			      surface_notify, draw))
280706f2543Smrg            return TRUE;
281706f2543Smrg        draw->pDraw = pDraw;
282706f2543Smrg    }
283706f2543Smrg
284706f2543Smrg    if (!context->isAttached || context->sid != draw->sid) {
285706f2543Smrg        x_list *lst;
286706f2543Smrg
287706f2543Smrg        if (xp_attach_gl_context(context->ctx, draw->sid) != Success) {
288706f2543Smrg	    //quartzProcs->DestroySurface(pDraw->pScreen, pDraw->id, pDraw,
289706f2543Smrg            DRIDestroySurface(pDraw->pScreen, pDraw->id, pDraw,
290706f2543Smrg			      surface_notify, draw);
291706f2543Smrg            if (surface_hash != NULL)
292706f2543Smrg                x_hash_table_remove(surface_hash, x_cvt_uint_to_vptr(draw->sid));
293706f2543Smrg
294706f2543Smrg            draw->sid = 0;
295706f2543Smrg            return TRUE;
296706f2543Smrg        }
297706f2543Smrg
298706f2543Smrg        context->isAttached = TRUE;
299706f2543Smrg        context->sid = draw->sid;
300706f2543Smrg
301706f2543Smrg        if (surface_hash == NULL)
302706f2543Smrg            surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
303706f2543Smrg
304706f2543Smrg        lst = x_hash_table_lookup(surface_hash, x_cvt_uint_to_vptr(context->sid), NULL);
305706f2543Smrg        if (x_list_find(lst, context) == NULL) {
306706f2543Smrg            lst = x_list_prepend(lst, context);
307706f2543Smrg            x_hash_table_insert(surface_hash, x_cvt_uint_to_vptr(context->sid), lst);
308706f2543Smrg        }
309706f2543Smrg
310706f2543Smrg
311706f2543Smrg
312706f2543Smrg        GLAQUA_DEBUG_MSG("attached 0x%x to 0x%x\n", (unsigned int) pDraw->id,
313706f2543Smrg                         (unsigned int) draw->sid);
314706f2543Smrg    }
315706f2543Smrg
316706f2543Smrg    draw->context = context;
317706f2543Smrg
318706f2543Smrg    return FALSE;
319706f2543Smrg}
320706f2543Smrg
321706f2543Smrg#if 0     // unused
322706f2543Smrgstatic void unattach(__GLXAquaContext *context) {
323706f2543Smrg	x_list *lst;
324706f2543Smrg	GLAQUA_DEBUG_MSG("unattach\n");
325706f2543Smrg	if (context == NULL) {
326706f2543Smrg		ErrorF("Tried to unattach a null context\n");
327706f2543Smrg		return;
328706f2543Smrg	}
329706f2543Smrg    if (context->isAttached) {
330706f2543Smrg        GLAQUA_DEBUG_MSG("unattaching\n");
331706f2543Smrg
332706f2543Smrg        if (surface_hash != NULL) {
333706f2543Smrg            lst = x_hash_table_lookup(surface_hash, (void *) context->sid, NULL);
334706f2543Smrg            lst = x_list_remove(lst, context);
335706f2543Smrg            x_hash_table_insert(surface_hash, (void *) context->sid, lst);
336706f2543Smrg        }
337706f2543Smrg
338706f2543Smrg        CGLClearDrawable(context->ctx);
339706f2543Smrg        context->isAttached = FALSE;
340706f2543Smrg        context->sid = 0;
341706f2543Smrg    }
342706f2543Smrg}
343706f2543Smrg#endif
344706f2543Smrg
345706f2543Smrgstatic int __glXAquaContextMakeCurrent(__GLXcontext *baseContext) {
346706f2543Smrg    CGLError gl_err;
347706f2543Smrg    __GLXAquaContext *context = (__GLXAquaContext *) baseContext;
348706f2543Smrg    __GLXAquaDrawable *drawPriv = (__GLXAquaDrawable *) context->base.drawPriv;
349706f2543Smrg
350706f2543Smrg    GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%p)\n", baseContext);
351706f2543Smrg
352706f2543Smrg    if(attach(context, drawPriv))
353706f2543Smrg	return /*error*/ 0;
354706f2543Smrg
355706f2543Smrg    gl_err = CGLSetCurrentContext(context->ctx);
356706f2543Smrg    if (gl_err != 0)
357706f2543Smrg        ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err));
358706f2543Smrg
359706f2543Smrg    return gl_err == 0;
360706f2543Smrg}
361706f2543Smrg
362706f2543Smrgstatic int __glXAquaContextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, unsigned long mask)
363706f2543Smrg{
364706f2543Smrg    CGLError gl_err;
365706f2543Smrg
366706f2543Smrg    __GLXAquaContext *dst = (__GLXAquaContext *) baseDst;
367706f2543Smrg    __GLXAquaContext *src = (__GLXAquaContext *) baseSrc;
368706f2543Smrg
369706f2543Smrg    GLAQUA_DEBUG_MSG("GLXAquaContextCopy\n");
370706f2543Smrg
371706f2543Smrg    gl_err = CGLCopyContext(src->ctx, dst->ctx, mask);
372706f2543Smrg    if (gl_err != 0)
373706f2543Smrg        ErrorF("CGLCopyContext error: %s\n", CGLErrorString(gl_err));
374706f2543Smrg
375706f2543Smrg    return gl_err == 0;
376706f2543Smrg}
377706f2543Smrg
378706f2543Smrgstatic int __glXAquaContextForceCurrent(__GLXcontext *baseContext)
379706f2543Smrg{
380706f2543Smrg    CGLError gl_err;
381706f2543Smrg    __GLXAquaContext *context = (__GLXAquaContext *) baseContext;
382706f2543Smrg    GLAQUA_DEBUG_MSG("glAquaForceCurrent (ctx %p)\n", context->ctx);
383706f2543Smrg
384706f2543Smrg    gl_err = CGLSetCurrentContext(context->ctx);
385706f2543Smrg    if (gl_err != 0)
386706f2543Smrg        ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err));
387706f2543Smrg
388706f2543Smrg    return gl_err == 0;
389706f2543Smrg}
390706f2543Smrg
391706f2543Smrg/* Drawing surface notification callbacks */
392706f2543Smrgstatic GLboolean __glXAquaDrawableSwapBuffers(ClientPtr client, __GLXdrawable *base) {
393706f2543Smrg    CGLError err;
394706f2543Smrg    __GLXAquaDrawable *drawable;
395706f2543Smrg
396706f2543Smrg    //    GLAQUA_DEBUG_MSG("glAquaDrawableSwapBuffers(%p)\n",base);
397706f2543Smrg
398706f2543Smrg    if(!base) {
399706f2543Smrg	ErrorF("%s passed NULL\n", __func__);
400706f2543Smrg	return GL_FALSE;
401706f2543Smrg    }
402706f2543Smrg
403706f2543Smrg    drawable = (__GLXAquaDrawable *)base;
404706f2543Smrg
405706f2543Smrg    if(NULL == drawable->context) {
406706f2543Smrg	ErrorF("%s called with a NULL->context for drawable %p!\n",
407706f2543Smrg	       __func__, (void *)drawable);
408706f2543Smrg	return GL_FALSE;
409706f2543Smrg    }
410706f2543Smrg
411706f2543Smrg    err = CGLFlushDrawable(drawable->context->ctx);
412706f2543Smrg
413706f2543Smrg    if(kCGLNoError != err) {
414706f2543Smrg	ErrorF("CGLFlushDrawable error: %s in %s\n", CGLErrorString(err),
415706f2543Smrg	       __func__);
416706f2543Smrg	return GL_FALSE;
417706f2543Smrg    }
418706f2543Smrg
419706f2543Smrg    return GL_TRUE;
420706f2543Smrg}
421706f2543Smrg
422706f2543Smrg
423706f2543Smrgstatic CGLPixelFormatObj makeFormat(__GLXconfig *conf) {
424706f2543Smrg    CGLPixelFormatAttribute attr[64];
425706f2543Smrg    CGLPixelFormatObj fobj;
426706f2543Smrg    GLint formats;
427706f2543Smrg    CGLError error;
428706f2543Smrg    int i = 0;
429706f2543Smrg
430706f2543Smrg    if(conf->doubleBufferMode)
431706f2543Smrg	attr[i++] = kCGLPFADoubleBuffer;
432706f2543Smrg
433706f2543Smrg    if(conf->stereoMode)
434706f2543Smrg	attr[i++] = kCGLPFAStereo;
435706f2543Smrg
436706f2543Smrg    attr[i++] = kCGLPFAColorSize;
437706f2543Smrg    attr[i++] = conf->redBits + conf->greenBits + conf->blueBits;
438706f2543Smrg    attr[i++] = kCGLPFAAlphaSize;
439706f2543Smrg    attr[i++] = conf->alphaBits;
440706f2543Smrg
441706f2543Smrg    if((conf->accumRedBits + conf->accumGreenBits + conf->accumBlueBits +
442706f2543Smrg	conf->accumAlphaBits) > 0) {
443706f2543Smrg
444706f2543Smrg	attr[i++] = kCGLPFAAccumSize;
445706f2543Smrg        attr[i++] = conf->accumRedBits + conf->accumGreenBits
446706f2543Smrg	    + conf->accumBlueBits + conf->accumAlphaBits;
447706f2543Smrg    }
448706f2543Smrg
449706f2543Smrg    attr[i++] = kCGLPFADepthSize;
450706f2543Smrg    attr[i++] = conf->depthBits;
451706f2543Smrg
452706f2543Smrg    if(conf->stencilBits) {
453706f2543Smrg	attr[i++] = kCGLPFAStencilSize;
454706f2543Smrg        attr[i++] = conf->stencilBits;
455706f2543Smrg    }
456706f2543Smrg
457706f2543Smrg    if(conf->numAuxBuffers > 0) {
458706f2543Smrg	attr[i++] = kCGLPFAAuxBuffers;
459706f2543Smrg	attr[i++] = conf->numAuxBuffers;
460706f2543Smrg    }
461706f2543Smrg
462706f2543Smrg    if(conf->sampleBuffers > 0) {
463706f2543Smrg       attr[i++] = kCGLPFASampleBuffers;
464706f2543Smrg       attr[i++] = conf->sampleBuffers;
465706f2543Smrg       attr[i++] = kCGLPFASamples;
466706f2543Smrg       attr[i++] = conf->samples;
467706f2543Smrg    }
468706f2543Smrg
469706f2543Smrg    attr[i] = 0;
470706f2543Smrg
471706f2543Smrg    error = CGLChoosePixelFormat(attr, &fobj, &formats);
472706f2543Smrg    if(error) {
473706f2543Smrg	ErrorF("error: creating pixel format %s\n", CGLErrorString(error));
474706f2543Smrg	return NULL;
475706f2543Smrg    }
476706f2543Smrg
477706f2543Smrg    return fobj;
478706f2543Smrg}
479706f2543Smrg
480706f2543Smrgstatic void __glXAquaScreenDestroy(__GLXscreen *screen) {
481706f2543Smrg
482706f2543Smrg    GLAQUA_DEBUG_MSG("glXAquaScreenDestroy(%p)\n", screen);
483706f2543Smrg    __glXScreenDestroy(screen);
484706f2543Smrg
485706f2543Smrg    free(screen);
486706f2543Smrg}
487706f2543Smrg
488706f2543Smrg/* This is called by __glXInitScreens(). */
489706f2543Smrgstatic __GLXscreen * __glXAquaScreenProbe(ScreenPtr pScreen) {
490706f2543Smrg    __GLXAquaScreen *screen;
491706f2543Smrg
492706f2543Smrg    GLAQUA_DEBUG_MSG("glXAquaScreenProbe\n");
493706f2543Smrg
494706f2543Smrg    if (pScreen == NULL)
495706f2543Smrg	return NULL;
496706f2543Smrg
497706f2543Smrg    screen = calloc(1, sizeof *screen);
498706f2543Smrg
499706f2543Smrg    if(NULL == screen)
500706f2543Smrg	return NULL;
501706f2543Smrg
502706f2543Smrg    screen->base.destroy        = __glXAquaScreenDestroy;
503706f2543Smrg    screen->base.createContext  = __glXAquaScreenCreateContext;
504706f2543Smrg    screen->base.createDrawable = __glXAquaScreenCreateDrawable;
505706f2543Smrg    screen->base.swapInterval = /*FIXME*/ NULL;
506706f2543Smrg    screen->base.pScreen       = pScreen;
507706f2543Smrg
508706f2543Smrg    screen->base.fbconfigs = __glXAquaCreateVisualConfigs(&screen->base.numFBConfigs, pScreen->myNum);
509706f2543Smrg
510706f2543Smrg    __glXScreenInit(&screen->base, pScreen);
511706f2543Smrg
512706f2543Smrg    screen->base.GLXmajor = 1;
513706f2543Smrg    screen->base.GLXminor = 4;
514706f2543Smrg    screen->base.GLXextensions = strdup("GLX_SGIX_fbconfig "
515706f2543Smrg                                        "GLX_SGIS_multisample "
516706f2543Smrg                                        "GLX_ARB_multisample "
517706f2543Smrg                                        "GLX_EXT_visual_info "
518706f2543Smrg                                        "GLX_EXT_import_context ");
519706f2543Smrg
520706f2543Smrg    /*We may be able to add more GLXextensions at a later time. */
521706f2543Smrg
522706f2543Smrg    return &screen->base;
523706f2543Smrg}
524706f2543Smrg
525706f2543Smrg#if 0 // unused
526706f2543Smrgstatic void __glXAquaDrawableCopySubBuffer (__GLXdrawable *drawable,
527706f2543Smrg					    int x, int y, int w, int h) {
528706f2543Smrg    /*TODO finish me*/
529706f2543Smrg}
530706f2543Smrg#endif
531706f2543Smrg
532706f2543Smrgstatic void __glXAquaDrawableDestroy(__GLXdrawable *base) {
533706f2543Smrg    /* gstaplin: base is the head of the structure, so it's at the same
534706f2543Smrg     * offset in memory.
535706f2543Smrg     * Is this safe with strict aliasing?   I noticed that the other dri code
536706f2543Smrg     * does this too...
537706f2543Smrg     */
538706f2543Smrg    __GLXAquaDrawable *glxPriv = (__GLXAquaDrawable *)base;
539706f2543Smrg
540706f2543Smrg    GLAQUA_DEBUG_MSG(__func__);
541706f2543Smrg
542706f2543Smrg    /* It doesn't work to call DRIDestroySurface here, the drawable's
543706f2543Smrg       already gone.. But dri.c notices the window destruction and
544706f2543Smrg       frees the surface itself. */
545706f2543Smrg
546706f2543Smrg    /*gstaplin: verify the statement above.  The surface destroy
547706f2543Smrg     *messages weren't making it through, and may still not be.
548706f2543Smrg     *We need a good test case for surface creation and destruction.
549706f2543Smrg     *We also need a good way to enable introspection on the server
550706f2543Smrg     *to validate the test, beyond using gdb with print.
551706f2543Smrg     */
552706f2543Smrg
553706f2543Smrg    free(glxPriv);
554706f2543Smrg}
555706f2543Smrg
556706f2543Smrgstatic __GLXdrawable *
557706f2543Smrg__glXAquaScreenCreateDrawable(ClientPtr client,
558706f2543Smrg                              __GLXscreen *screen,
559706f2543Smrg			      DrawablePtr pDraw,
560706f2543Smrg			      XID drawId,
561706f2543Smrg			      int type,
562706f2543Smrg			      XID glxDrawId,
563706f2543Smrg			      __GLXconfig *conf) {
564706f2543Smrg  __GLXAquaDrawable *glxPriv;
565706f2543Smrg
566706f2543Smrg  glxPriv = malloc(sizeof *glxPriv);
567706f2543Smrg
568706f2543Smrg  if(glxPriv == NULL)
569706f2543Smrg      return NULL;
570706f2543Smrg
571706f2543Smrg  memset(glxPriv, 0, sizeof *glxPriv);
572706f2543Smrg
573706f2543Smrg  if(!__glXDrawableInit(&glxPriv->base, screen, pDraw, type, glxDrawId, conf)) {
574706f2543Smrg    free(glxPriv);
575706f2543Smrg    return NULL;
576706f2543Smrg  }
577706f2543Smrg
578706f2543Smrg  glxPriv->base.destroy       = __glXAquaDrawableDestroy;
579706f2543Smrg  glxPriv->base.swapBuffers   = __glXAquaDrawableSwapBuffers;
580706f2543Smrg  glxPriv->base.copySubBuffer = NULL; /* __glXAquaDrawableCopySubBuffer; */
581706f2543Smrg
582706f2543Smrg  glxPriv->pDraw = pDraw;
583706f2543Smrg  glxPriv->sid = 0;
584706f2543Smrg  glxPriv->context = NULL;
585706f2543Smrg
586706f2543Smrg  return &glxPriv->base;
587706f2543Smrg}
588706f2543Smrg
589706f2543Smrg// Extra goodies for glx
590706f2543Smrg
591706f2543SmrgGLuint __glFloorLog2(GLuint val)
592706f2543Smrg{
593706f2543Smrg    int c = 0;
594706f2543Smrg
595706f2543Smrg    while (val > 1) {
596706f2543Smrg        c++;
597706f2543Smrg        val >>= 1;
598706f2543Smrg    }
599706f2543Smrg    return c;
600706f2543Smrg}
601706f2543Smrg
602706f2543Smrg#ifndef OPENGL_FRAMEWORK_PATH
603706f2543Smrg#define OPENGL_FRAMEWORK_PATH "/System/Library/Frameworks/OpenGL.framework/OpenGL"
604706f2543Smrg#endif
605706f2543Smrg
606706f2543Smrgstatic void setup_dispatch_table(void) {
607706f2543Smrg    static struct _glapi_table *disp = NULL;
608706f2543Smrg    static void *handle;
609706f2543Smrg    const char *opengl_framework_path;
610706f2543Smrg
611706f2543Smrg    if(disp)  {
612706f2543Smrg        _glapi_set_dispatch(disp);
613706f2543Smrg        return;
614706f2543Smrg    }
615706f2543Smrg
616706f2543Smrg    opengl_framework_path = getenv("OPENGL_FRAMEWORK_PATH");
617706f2543Smrg    if (!opengl_framework_path) {
618706f2543Smrg        opengl_framework_path = OPENGL_FRAMEWORK_PATH;
619706f2543Smrg    }
620706f2543Smrg
621706f2543Smrg    (void) dlerror();            /*drain dlerror */
622706f2543Smrg    handle = dlopen(opengl_framework_path, RTLD_LOCAL);
623706f2543Smrg
624706f2543Smrg    if (!handle) {
625706f2543Smrg        ErrorF("unable to dlopen %s : %s, using RTLD_DEFAULT\n",
626706f2543Smrg                opengl_framework_path, dlerror());
627706f2543Smrg        handle = RTLD_DEFAULT;
628706f2543Smrg    }
629706f2543Smrg
630706f2543Smrg    disp = _glapi_create_table_from_handle(handle, "gl");
631706f2543Smrg    assert(disp);
632706f2543Smrg
633706f2543Smrg    _glapi_set_dispatch(disp);
634706f2543Smrg}
635