1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 2008 Apple Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice shall be included in
12706f2543Smrg * all copies or substantial portions of the Software.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20706f2543Smrg * DEALINGS IN THE SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include <stdio.h>
24706f2543Smrg#include <stdlib.h>
25706f2543Smrg#include <assert.h>
26706f2543Smrg#include <OpenGL/OpenGL.h>
27706f2543Smrg#include <OpenGL/gl.h>
28706f2543Smrg#include <OpenGL/glu.h>
29706f2543Smrg#include <OpenGL/glext.h>
30706f2543Smrg#include <ApplicationServices/ApplicationServices.h>
31706f2543Smrg
32706f2543Smrg#include "capabilities.h"
33706f2543Smrg
34706f2543Smrg#define Cursor X_Cursor
35706f2543Smrg#include "os.h"
36706f2543Smrg#undef Cursor
37706f2543Smrg
38706f2543Smrgstatic void handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes) {
39706f2543Smrg    if(bufferModes & kCGLStereoscopicBit) {
40706f2543Smrg	c->stereo = true;
41706f2543Smrg    }
42706f2543Smrg
43706f2543Smrg    if(bufferModes & kCGLDoubleBufferBit) {
44706f2543Smrg	c->buffers = 2;
45706f2543Smrg    } else {
46706f2543Smrg	c->buffers = 1;
47706f2543Smrg    }
48706f2543Smrg}
49706f2543Smrg
50706f2543Smrgstatic void handleStencilModes(struct glCapabilitiesConfig *c, GLint smodes) {
51706f2543Smrg    int offset = 0;
52706f2543Smrg
53706f2543Smrg    if(kCGL0Bit & smodes)
54706f2543Smrg	c->stencil_bit_depths[offset++] = 0;
55706f2543Smrg
56706f2543Smrg    if(kCGL1Bit & smodes)
57706f2543Smrg	c->stencil_bit_depths[offset++] = 1;
58706f2543Smrg
59706f2543Smrg    if(kCGL2Bit & smodes)
60706f2543Smrg	c->stencil_bit_depths[offset++] = 2;
61706f2543Smrg
62706f2543Smrg    if(kCGL3Bit & smodes)
63706f2543Smrg	c->stencil_bit_depths[offset++] = 3;
64706f2543Smrg
65706f2543Smrg    if(kCGL4Bit & smodes)
66706f2543Smrg	c->stencil_bit_depths[offset++] = 4;
67706f2543Smrg
68706f2543Smrg    if(kCGL5Bit & smodes)
69706f2543Smrg	c->stencil_bit_depths[offset++] = 5;
70706f2543Smrg
71706f2543Smrg    if(kCGL6Bit & smodes)
72706f2543Smrg	c->stencil_bit_depths[offset++] = 6;
73706f2543Smrg
74706f2543Smrg    if(kCGL8Bit & smodes)
75706f2543Smrg	c->stencil_bit_depths[offset++] = 8;
76706f2543Smrg
77706f2543Smrg    if(kCGL10Bit & smodes)
78706f2543Smrg	c->stencil_bit_depths[offset++] = 10;
79706f2543Smrg
80706f2543Smrg    if(kCGL12Bit & smodes)
81706f2543Smrg	c->stencil_bit_depths[offset++] = 12;
82706f2543Smrg
83706f2543Smrg    if(kCGL16Bit & smodes)
84706f2543Smrg	c->stencil_bit_depths[offset++] = 16;
85706f2543Smrg
86706f2543Smrg    if(kCGL24Bit & smodes)
87706f2543Smrg	c->stencil_bit_depths[offset++] = 24;
88706f2543Smrg
89706f2543Smrg    if(kCGL32Bit & smodes)
90706f2543Smrg	c->stencil_bit_depths[offset++] = 32;
91706f2543Smrg
92706f2543Smrg    if(kCGL48Bit & smodes)
93706f2543Smrg	c->stencil_bit_depths[offset++] = 48;
94706f2543Smrg
95706f2543Smrg    if(kCGL64Bit & smodes)
96706f2543Smrg	c->stencil_bit_depths[offset++] = 64;
97706f2543Smrg
98706f2543Smrg    if(kCGL96Bit & smodes)
99706f2543Smrg	c->stencil_bit_depths[offset++] = 96;
100706f2543Smrg
101706f2543Smrg    if(kCGL128Bit & smodes)
102706f2543Smrg	c->stencil_bit_depths[offset++] = 128;
103706f2543Smrg
104706f2543Smrg    assert(offset < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS);
105706f2543Smrg
106706f2543Smrg    c->total_stencil_bit_depths = offset;
107706f2543Smrg}
108706f2543Smrg
109706f2543Smrgstatic int handleColorAndAccumulation(struct glColorBufCapabilities *c,
110706f2543Smrg				       GLint cmodes, int forAccum) {
111706f2543Smrg    int offset = 0;
112706f2543Smrg
113706f2543Smrg    /*1*/
114706f2543Smrg    if(kCGLRGB444Bit & cmodes) {
115706f2543Smrg	c[offset].r = 4;
116706f2543Smrg	c[offset].g = 4;
117706f2543Smrg	c[offset].b = 4;
118706f2543Smrg	++offset;
119706f2543Smrg    }
120706f2543Smrg
121706f2543Smrg    /*2*/
122706f2543Smrg    if(kCGLARGB4444Bit & cmodes) {
123706f2543Smrg	c[offset].a = 4;
124706f2543Smrg	c[offset].r = 4;
125706f2543Smrg	c[offset].g = 4;
126706f2543Smrg	c[offset].b = 4;
127706f2543Smrg	c[offset].is_argb = true;
128706f2543Smrg	++offset;
129706f2543Smrg    }
130706f2543Smrg
131706f2543Smrg    /*3*/
132706f2543Smrg    if(kCGLRGB444A8Bit & cmodes) {
133706f2543Smrg	c[offset].r = 4;
134706f2543Smrg	c[offset].g = 4;
135706f2543Smrg	c[offset].b = 4;
136706f2543Smrg	c[offset].a = 8;
137706f2543Smrg	++offset;
138706f2543Smrg    }
139706f2543Smrg
140706f2543Smrg    /*4*/
141706f2543Smrg    if(kCGLRGB555Bit & cmodes) {
142706f2543Smrg	c[offset].r = 5;
143706f2543Smrg	c[offset].g = 5;
144706f2543Smrg	c[offset].b = 5;
145706f2543Smrg	++offset;
146706f2543Smrg    }
147706f2543Smrg
148706f2543Smrg    /*5*/
149706f2543Smrg    if(kCGLARGB1555Bit & cmodes) {
150706f2543Smrg	c[offset].a = 1;
151706f2543Smrg	c[offset].r = 5;
152706f2543Smrg	c[offset].g = 5;
153706f2543Smrg	c[offset].b = 5;
154706f2543Smrg	c[offset].is_argb = true;
155706f2543Smrg	++offset;
156706f2543Smrg    }
157706f2543Smrg
158706f2543Smrg    /*6*/
159706f2543Smrg    if(kCGLRGB555A8Bit & cmodes) {
160706f2543Smrg	c[offset].r = 5;
161706f2543Smrg	c[offset].g = 5;
162706f2543Smrg	c[offset].b = 5;
163706f2543Smrg	c[offset].a = 8;
164706f2543Smrg	++offset;
165706f2543Smrg    }
166706f2543Smrg
167706f2543Smrg    /*7*/
168706f2543Smrg    if(kCGLRGB565Bit & cmodes) {
169706f2543Smrg	c[offset].r = 5;
170706f2543Smrg	c[offset].g = 6;
171706f2543Smrg	c[offset].b = 5;
172706f2543Smrg	++offset;
173706f2543Smrg    }
174706f2543Smrg
175706f2543Smrg    /*8*/
176706f2543Smrg    if(kCGLRGB565A8Bit & cmodes) {
177706f2543Smrg	c[offset].r = 5;
178706f2543Smrg	c[offset].g = 6;
179706f2543Smrg	c[offset].b = 5;
180706f2543Smrg	c[offset].a = 8;
181706f2543Smrg	++offset;
182706f2543Smrg    }
183706f2543Smrg
184706f2543Smrg    /*9*/
185706f2543Smrg    if(kCGLRGB888Bit & cmodes) {
186706f2543Smrg	c[offset].r = 8;
187706f2543Smrg	c[offset].g = 8;
188706f2543Smrg	c[offset].b = 8;
189706f2543Smrg	++offset;
190706f2543Smrg    }
191706f2543Smrg
192706f2543Smrg    /*10*/
193706f2543Smrg    if(kCGLARGB8888Bit & cmodes) {
194706f2543Smrg	c[offset].a = 8;
195706f2543Smrg	c[offset].r = 8;
196706f2543Smrg	c[offset].g = 8;
197706f2543Smrg	c[offset].b = 8;
198706f2543Smrg	c[offset].is_argb = true;
199706f2543Smrg	++offset;
200706f2543Smrg    }
201706f2543Smrg
202706f2543Smrg    /*11*/
203706f2543Smrg    if(kCGLRGB888A8Bit & cmodes) {
204706f2543Smrg	c[offset].r = 8;
205706f2543Smrg	c[offset].g = 8;
206706f2543Smrg	c[offset].b = 8;
207706f2543Smrg	c[offset].a = 8;
208706f2543Smrg	++offset;
209706f2543Smrg    }
210706f2543Smrg
211706f2543Smrg    if(forAccum) {
212706f2543Smrg//#if 0
213706f2543Smrg    /* FIXME
214706f2543Smrg     * Disable this path, because some part of libGL, X, or Xplugin
215706f2543Smrg     * doesn't work with sizes greater than 8.
216706f2543Smrg     * When this is enabled and visuals are chosen using depths
217706f2543Smrg     * such as 16, the result is that the windows don't redraw
218706f2543Smrg     * and are often white, until a resize.
219706f2543Smrg     */
220706f2543Smrg
221706f2543Smrg    /*12*/
222706f2543Smrg    if(kCGLRGB101010Bit & cmodes) {
223706f2543Smrg	c[offset].r = 10;
224706f2543Smrg	c[offset].g = 10;
225706f2543Smrg	c[offset].b = 10;
226706f2543Smrg	++offset;
227706f2543Smrg    }
228706f2543Smrg
229706f2543Smrg    /*13*/
230706f2543Smrg    if(kCGLARGB2101010Bit & cmodes) {
231706f2543Smrg	c[offset].a = 2;
232706f2543Smrg	c[offset].r = 10;
233706f2543Smrg	c[offset].g = 10;
234706f2543Smrg	c[offset].b = 10;
235706f2543Smrg	c[offset].is_argb = true;
236706f2543Smrg	++offset;
237706f2543Smrg    }
238706f2543Smrg
239706f2543Smrg    /*14*/
240706f2543Smrg    if(kCGLRGB101010_A8Bit & cmodes) {
241706f2543Smrg	c[offset].r = 10;
242706f2543Smrg	c[offset].g = 10;
243706f2543Smrg	c[offset].b = 10;
244706f2543Smrg	c[offset].a = 8;
245706f2543Smrg	++offset;
246706f2543Smrg    }
247706f2543Smrg
248706f2543Smrg    /*15*/
249706f2543Smrg    if(kCGLRGB121212Bit & cmodes) {
250706f2543Smrg	c[offset].r = 12;
251706f2543Smrg	c[offset].g = 12;
252706f2543Smrg	c[offset].b = 12;
253706f2543Smrg	++offset;
254706f2543Smrg    }
255706f2543Smrg
256706f2543Smrg    /*16*/
257706f2543Smrg    if(kCGLARGB12121212Bit & cmodes) {
258706f2543Smrg	c[offset].a = 12;
259706f2543Smrg	c[offset].r = 12;
260706f2543Smrg	c[offset].g = 12;
261706f2543Smrg	c[offset].b = 12;
262706f2543Smrg	c[offset].is_argb = true;
263706f2543Smrg	++offset;
264706f2543Smrg    }
265706f2543Smrg
266706f2543Smrg    /*17*/
267706f2543Smrg    if(kCGLRGB161616Bit & cmodes) {
268706f2543Smrg	c[offset].r = 16;
269706f2543Smrg	c[offset].g = 16;
270706f2543Smrg	c[offset].b = 16;
271706f2543Smrg	++offset;
272706f2543Smrg    }
273706f2543Smrg
274706f2543Smrg    /*18*/
275706f2543Smrg    if(kCGLRGBA16161616Bit & cmodes) {
276706f2543Smrg	c[offset].r = 16;
277706f2543Smrg	c[offset].g = 16;
278706f2543Smrg	c[offset].b = 16;
279706f2543Smrg	c[offset].a = 16;
280706f2543Smrg	++offset;
281706f2543Smrg    }
282706f2543Smrg    }
283706f2543Smrg//#endif
284706f2543Smrg
285706f2543Smrg    /* FIXME should we handle the floating point color modes, and if so, how? */
286706f2543Smrg
287706f2543Smrg    return offset;
288706f2543Smrg}
289706f2543Smrg
290706f2543Smrg
291706f2543Smrgstatic void handleColorModes(struct glCapabilitiesConfig *c, GLint cmodes) {
292706f2543Smrg    c->total_color_buffers = handleColorAndAccumulation(c->color_buffers,
293706f2543Smrg							cmodes, 0);
294706f2543Smrg
295706f2543Smrg    assert(c->total_color_buffers < GLCAPS_COLOR_BUFFERS);
296706f2543Smrg}
297706f2543Smrg
298706f2543Smrgstatic void handleAccumulationModes(struct glCapabilitiesConfig *c, GLint cmodes) {
299706f2543Smrg    c->total_accum_buffers = handleColorAndAccumulation(c->accum_buffers,
300706f2543Smrg							cmodes, 1);
301706f2543Smrg    assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS);
302706f2543Smrg}
303706f2543Smrg
304706f2543Smrgstatic void handleDepthModes(struct glCapabilitiesConfig *c, GLint dmodes) {
305706f2543Smrg    int offset = 0;
306706f2543Smrg#define DEPTH(flag,value) do { \
307706f2543Smrg	if(dmodes & flag) { \
308706f2543Smrg	    c->depth_buffers[offset++] = value; \
309706f2543Smrg	} \
310706f2543Smrg    } while(0)
311706f2543Smrg
312706f2543Smrg    /*1*/
313706f2543Smrg    DEPTH(kCGL0Bit, 0);
314706f2543Smrg    /*2*/
315706f2543Smrg    DEPTH(kCGL1Bit, 1);
316706f2543Smrg    /*3*/
317706f2543Smrg    DEPTH(kCGL2Bit, 2);
318706f2543Smrg    /*4*/
319706f2543Smrg    DEPTH(kCGL3Bit, 3);
320706f2543Smrg    /*5*/
321706f2543Smrg    DEPTH(kCGL4Bit, 4);
322706f2543Smrg    /*6*/
323706f2543Smrg    DEPTH(kCGL5Bit, 5);
324706f2543Smrg    /*7*/
325706f2543Smrg    DEPTH(kCGL6Bit, 6);
326706f2543Smrg    /*8*/
327706f2543Smrg    DEPTH(kCGL8Bit, 8);
328706f2543Smrg    /*9*/
329706f2543Smrg    DEPTH(kCGL10Bit, 10);
330706f2543Smrg    /*10*/
331706f2543Smrg    DEPTH(kCGL12Bit, 12);
332706f2543Smrg    /*11*/
333706f2543Smrg    DEPTH(kCGL16Bit, 16);
334706f2543Smrg    /*12*/
335706f2543Smrg    DEPTH(kCGL24Bit, 24);
336706f2543Smrg    /*13*/
337706f2543Smrg    DEPTH(kCGL32Bit, 32);
338706f2543Smrg    /*14*/
339706f2543Smrg    DEPTH(kCGL48Bit, 48);
340706f2543Smrg    /*15*/
341706f2543Smrg    DEPTH(kCGL64Bit, 64);
342706f2543Smrg    /*16*/
343706f2543Smrg    DEPTH(kCGL96Bit, 96);
344706f2543Smrg    /*17*/
345706f2543Smrg    DEPTH(kCGL128Bit, 128);
346706f2543Smrg
347706f2543Smrg#undef DEPTH
348706f2543Smrg
349706f2543Smrg    c->total_depth_buffer_depths = offset;
350706f2543Smrg    assert(c->total_depth_buffer_depths < GLCAPS_DEPTH_BUFFERS);
351706f2543Smrg}
352706f2543Smrg
353706f2543Smrg/* Return non-zero if an error occured. */
354706f2543Smrgstatic CGLError handleRendererDescriptions(CGLRendererInfoObj info, GLint r,
355706f2543Smrg					   struct glCapabilitiesConfig *c) {
356706f2543Smrg    CGLError err;
357706f2543Smrg    GLint accelerated = 0, flags = 0, aux = 0, samplebufs = 0, samples = 0;
358706f2543Smrg
359706f2543Smrg    err = CGLDescribeRenderer (info, r, kCGLRPAccelerated, &accelerated);
360706f2543Smrg
361706f2543Smrg    if(err)
362706f2543Smrg	return err;
363706f2543Smrg
364706f2543Smrg    c->accelerated = accelerated;
365706f2543Smrg
366706f2543Smrg    /* Buffering modes: single/double, stereo */
367706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags);
368706f2543Smrg
369706f2543Smrg    if(err)
370706f2543Smrg	return err;
371706f2543Smrg
372706f2543Smrg    handleBufferModes(c, flags);
373706f2543Smrg
374706f2543Smrg    /* AUX buffers */
375706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux);
376706f2543Smrg
377706f2543Smrg    if(err)
378706f2543Smrg	return err;
379706f2543Smrg
380706f2543Smrg    c->aux_buffers = aux;
381706f2543Smrg
382706f2543Smrg
383706f2543Smrg    /* Depth buffer size */
384706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPDepthModes, &flags);
385706f2543Smrg
386706f2543Smrg    if(err)
387706f2543Smrg	return err;
388706f2543Smrg
389706f2543Smrg    handleDepthModes(c, flags);
390706f2543Smrg
391706f2543Smrg
392706f2543Smrg    /* Multisample buffers */
393706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPMaxSampleBuffers, &samplebufs);
394706f2543Smrg
395706f2543Smrg    if(err)
396706f2543Smrg	return err;
397706f2543Smrg
398706f2543Smrg    c->multisample_buffers = samplebufs;
399706f2543Smrg
400706f2543Smrg
401706f2543Smrg    /* Multisample samples per multisample buffer */
402706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPMaxSamples, &samples);
403706f2543Smrg
404706f2543Smrg    if(err)
405706f2543Smrg	return err;
406706f2543Smrg
407706f2543Smrg    c->multisample_samples = samples;
408706f2543Smrg
409706f2543Smrg
410706f2543Smrg    /* Stencil bit depths */
411706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPStencilModes, &flags);
412706f2543Smrg
413706f2543Smrg    if(err)
414706f2543Smrg	return err;
415706f2543Smrg
416706f2543Smrg    handleStencilModes(c, flags);
417706f2543Smrg
418706f2543Smrg
419706f2543Smrg    /* Color modes (RGB/RGBA depths supported */
420706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPColorModes, &flags);
421706f2543Smrg
422706f2543Smrg    if(err)
423706f2543Smrg	return err;
424706f2543Smrg
425706f2543Smrg    handleColorModes(c, flags);
426706f2543Smrg
427706f2543Smrg    err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags);
428706f2543Smrg
429706f2543Smrg    if(err)
430706f2543Smrg	return err;
431706f2543Smrg
432706f2543Smrg    handleAccumulationModes(c, flags);
433706f2543Smrg
434706f2543Smrg    return kCGLNoError;
435706f2543Smrg}
436706f2543Smrg
437706f2543Smrgstatic void initCapabilities(struct glCapabilities *cap) {
438706f2543Smrg    cap->configurations = NULL;
439706f2543Smrg    cap->total_configurations = 0;
440706f2543Smrg}
441706f2543Smrg
442706f2543Smrgstatic void initConfig(struct glCapabilitiesConfig *c) {
443706f2543Smrg    int i;
444706f2543Smrg
445706f2543Smrg    c->accelerated = false;
446706f2543Smrg    c->stereo = false;
447706f2543Smrg    c->aux_buffers = 0;
448706f2543Smrg    c->buffers = 0;
449706f2543Smrg
450706f2543Smrg    c->total_depth_buffer_depths = 0;
451706f2543Smrg
452706f2543Smrg    for(i = 0; i < GLCAPS_DEPTH_BUFFERS; ++i) {
453706f2543Smrg	c->depth_buffers[i] = GLCAPS_INVALID_DEPTH_VALUE;
454706f2543Smrg    }
455706f2543Smrg
456706f2543Smrg    c->multisample_buffers = 0;
457706f2543Smrg    c->multisample_samples = 0;
458706f2543Smrg
459706f2543Smrg    c->total_stencil_bit_depths = 0;
460706f2543Smrg
461706f2543Smrg    for(i = 0; i < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS; ++i) {
462706f2543Smrg	c->stencil_bit_depths[i] = GLCAPS_INVALID_STENCIL_DEPTH;
463706f2543Smrg    }
464706f2543Smrg
465706f2543Smrg    c->total_color_buffers = 0;
466706f2543Smrg
467706f2543Smrg    for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
468706f2543Smrg	c->color_buffers[i].r =	c->color_buffers[i].g =
469706f2543Smrg	    c->color_buffers[i].b = c->color_buffers[i].a =
470706f2543Smrg	    GLCAPS_COLOR_BUF_INVALID_VALUE;
471706f2543Smrg	c->color_buffers[i].is_argb = false;
472706f2543Smrg     }
473706f2543Smrg
474706f2543Smrg    c->total_accum_buffers = 0;
475706f2543Smrg
476706f2543Smrg    for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
477706f2543Smrg	c->accum_buffers[i].r = c->accum_buffers[i].g =
478706f2543Smrg	    c->accum_buffers[i].b = c->accum_buffers[i].a =
479706f2543Smrg	    GLCAPS_COLOR_BUF_INVALID_VALUE;
480706f2543Smrg	c->accum_buffers[i].is_argb = false;
481706f2543Smrg    }
482706f2543Smrg
483706f2543Smrg    c->next = NULL;
484706f2543Smrg}
485706f2543Smrg
486706f2543Smrgvoid freeGlCapabilities(struct glCapabilities *cap) {
487706f2543Smrg    struct glCapabilitiesConfig *conf, *next;
488706f2543Smrg
489706f2543Smrg    conf = cap->configurations;
490706f2543Smrg
491706f2543Smrg    while(conf) {
492706f2543Smrg	next = conf->next;
493706f2543Smrg	free(conf);
494706f2543Smrg	conf = next;
495706f2543Smrg    }
496706f2543Smrg
497706f2543Smrg    cap->configurations = NULL;
498706f2543Smrg}
499706f2543Smrg
500706f2543Smrg/*Return true if an error occured. */
501706f2543Smrgbool getGlCapabilities(struct glCapabilities *cap) {
502706f2543Smrg	CGLRendererInfoObj info;
503706f2543Smrg    CGLError err;
504706f2543Smrg	GLint numRenderers = 0, r;
505706f2543Smrg
506706f2543Smrg    initCapabilities(cap);
507706f2543Smrg
508706f2543Smrg	err = CGLQueryRendererInfo((GLuint)-1, &info, &numRenderers);
509706f2543Smrg    if(err) {
510706f2543Smrg	    fprintf(stderr, "CGLQueryRendererInfo error: %s\n", CGLErrorString(err));
511706f2543Smrg        return err;
512706f2543Smrg	}
513706f2543Smrg
514706f2543Smrg	for(r = 0; r < numRenderers; r++) {
515706f2543Smrg	    struct glCapabilitiesConfig tmpconf, *conf;
516706f2543Smrg
517706f2543Smrg	    initConfig(&tmpconf);
518706f2543Smrg
519706f2543Smrg	    err = handleRendererDescriptions(info, r, &tmpconf);
520706f2543Smrg	    if(err) {
521706f2543Smrg            fprintf(stderr, "handleRendererDescriptions returned error: %s\n", CGLErrorString(err));
522706f2543Smrg            fprintf(stderr, "trying to continue...\n");
523706f2543Smrg            continue;
524706f2543Smrg	    }
525706f2543Smrg
526706f2543Smrg	    conf = malloc(sizeof(*conf));
527706f2543Smrg	    if(NULL == conf) {
528706f2543Smrg                FatalError("Unable to allocate memory for OpenGL capabilities\n");
529706f2543Smrg	    }
530706f2543Smrg
531706f2543Smrg	    /* Copy the struct. */
532706f2543Smrg	    *conf = tmpconf;
533706f2543Smrg
534706f2543Smrg	    /* Now link the configuration into the list. */
535706f2543Smrg	    conf->next = cap->configurations;
536706f2543Smrg	    cap->configurations = conf;
537706f2543Smrg	}
538706f2543Smrg
539706f2543Smrg    CGLDestroyRendererInfo(info);
540706f2543Smrg
541706f2543Smrg    /* No error occured.  We are done. */
542706f2543Smrg    return kCGLNoError;
543706f2543Smrg}
544