1 /*
2  * Copyright (c) 2008-2012 Apple Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 
31 #define Cursor Mac_Cursor
32 #define BOOL   Mac_BOOL
33 #include <OpenGL/OpenGL.h>
34 #include <OpenGL/gl.h>
35 #include <OpenGL/glu.h>
36 #include <OpenGL/glext.h>
37 #include <ApplicationServices/ApplicationServices.h>
38 #undef Cursor
39 #undef BOOL
40 
41 #include "capabilities.h"
42 
43 #include "os.h"
44 
45 static void
handleBufferModes(struct glCapabilitiesConfig * c,GLint bufferModes)46 handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes)
47 {
48     if (bufferModes & kCGLStereoscopicBit) {
49         c->stereo = true;
50     }
51 
52     if (bufferModes & kCGLDoubleBufferBit) {
53         c->buffers = 2;
54     }
55     else {
56         c->buffers = 1;
57     }
58 }
59 
60 static void
handleStencilModes(struct glCapabilitiesConfig * c,GLint smodes)61 handleStencilModes(struct glCapabilitiesConfig *c, GLint smodes)
62 {
63     int offset = 0;
64 
65     if (kCGL0Bit & smodes)
66         c->stencil_bit_depths[offset++] = 0;
67 
68     if (kCGL1Bit & smodes)
69         c->stencil_bit_depths[offset++] = 1;
70 
71     if (kCGL2Bit & smodes)
72         c->stencil_bit_depths[offset++] = 2;
73 
74     if (kCGL3Bit & smodes)
75         c->stencil_bit_depths[offset++] = 3;
76 
77     if (kCGL4Bit & smodes)
78         c->stencil_bit_depths[offset++] = 4;
79 
80     if (kCGL5Bit & smodes)
81         c->stencil_bit_depths[offset++] = 5;
82 
83     if (kCGL6Bit & smodes)
84         c->stencil_bit_depths[offset++] = 6;
85 
86     if (kCGL8Bit & smodes)
87         c->stencil_bit_depths[offset++] = 8;
88 
89     if (kCGL10Bit & smodes)
90         c->stencil_bit_depths[offset++] = 10;
91 
92     if (kCGL12Bit & smodes)
93         c->stencil_bit_depths[offset++] = 12;
94 
95     if (kCGL16Bit & smodes)
96         c->stencil_bit_depths[offset++] = 16;
97 
98     if (kCGL24Bit & smodes)
99         c->stencil_bit_depths[offset++] = 24;
100 
101     if (kCGL32Bit & smodes)
102         c->stencil_bit_depths[offset++] = 32;
103 
104     if (kCGL48Bit & smodes)
105         c->stencil_bit_depths[offset++] = 48;
106 
107     if (kCGL64Bit & smodes)
108         c->stencil_bit_depths[offset++] = 64;
109 
110     if (kCGL96Bit & smodes)
111         c->stencil_bit_depths[offset++] = 96;
112 
113     if (kCGL128Bit & smodes)
114         c->stencil_bit_depths[offset++] = 128;
115 
116     assert(offset < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS);
117 
118     c->total_stencil_bit_depths = offset;
119 }
120 
121 static int
handleColorAndAccumulation(struct glColorBufCapabilities * c,GLint cmodes,int forAccum)122 handleColorAndAccumulation(struct glColorBufCapabilities *c,
123                            GLint cmodes, int forAccum)
124 {
125     int offset = 0;
126 
127     /*1*/
128     if (kCGLRGB444Bit & cmodes) {
129         c[offset].r = 4;
130         c[offset].g = 4;
131         c[offset].b = 4;
132         ++offset;
133     }
134 
135     /*2*/
136     if (kCGLARGB4444Bit & cmodes) {
137         c[offset].a = 4;
138         c[offset].r = 4;
139         c[offset].g = 4;
140         c[offset].b = 4;
141         c[offset].is_argb = true;
142         ++offset;
143     }
144 
145     /*3*/
146     if (kCGLRGB444A8Bit & cmodes) {
147         c[offset].r = 4;
148         c[offset].g = 4;
149         c[offset].b = 4;
150         c[offset].a = 8;
151         ++offset;
152     }
153 
154     /*4*/
155     if (kCGLRGB555Bit & cmodes) {
156         c[offset].r = 5;
157         c[offset].g = 5;
158         c[offset].b = 5;
159         ++offset;
160     }
161 
162     /*5*/
163     if (kCGLARGB1555Bit & cmodes) {
164         c[offset].a = 1;
165         c[offset].r = 5;
166         c[offset].g = 5;
167         c[offset].b = 5;
168         c[offset].is_argb = true;
169         ++offset;
170     }
171 
172     /*6*/
173     if (kCGLRGB555A8Bit & cmodes) {
174         c[offset].r = 5;
175         c[offset].g = 5;
176         c[offset].b = 5;
177         c[offset].a = 8;
178         ++offset;
179     }
180 
181     /*7*/
182     if (kCGLRGB565Bit & cmodes) {
183         c[offset].r = 5;
184         c[offset].g = 6;
185         c[offset].b = 5;
186         ++offset;
187     }
188 
189     /*8*/
190     if (kCGLRGB565A8Bit & cmodes) {
191         c[offset].r = 5;
192         c[offset].g = 6;
193         c[offset].b = 5;
194         c[offset].a = 8;
195         ++offset;
196     }
197 
198     /*9*/
199     if (kCGLRGB888Bit & cmodes) {
200         c[offset].r = 8;
201         c[offset].g = 8;
202         c[offset].b = 8;
203         ++offset;
204     }
205 
206     /*10*/
207     if (kCGLARGB8888Bit & cmodes) {
208         c[offset].a = 8;
209         c[offset].r = 8;
210         c[offset].g = 8;
211         c[offset].b = 8;
212         c[offset].is_argb = true;
213         ++offset;
214     }
215 
216     /*11*/
217     if (kCGLRGB888A8Bit & cmodes) {
218         c[offset].r = 8;
219         c[offset].g = 8;
220         c[offset].b = 8;
221         c[offset].a = 8;
222         ++offset;
223     }
224 
225     if (forAccum) {
226         //#if 0
227         /* FIXME
228          * Disable this path, because some part of libGL, X, or Xplugin
229          * doesn't work with sizes greater than 8.
230          * When this is enabled and visuals are chosen using depths
231          * such as 16, the result is that the windows don't redraw
232          * and are often white, until a resize.
233          */
234 
235         /*12*/
236         if (kCGLRGB101010Bit & cmodes) {
237             c[offset].r = 10;
238             c[offset].g = 10;
239             c[offset].b = 10;
240             ++offset;
241         }
242 
243         /*13*/
244         if (kCGLARGB2101010Bit & cmodes) {
245             c[offset].a = 2;
246             c[offset].r = 10;
247             c[offset].g = 10;
248             c[offset].b = 10;
249             c[offset].is_argb = true;
250             ++offset;
251         }
252 
253         /*14*/
254         if (kCGLRGB101010_A8Bit & cmodes) {
255             c[offset].r = 10;
256             c[offset].g = 10;
257             c[offset].b = 10;
258             c[offset].a = 8;
259             ++offset;
260         }
261 
262         /*15*/
263         if (kCGLRGB121212Bit & cmodes) {
264             c[offset].r = 12;
265             c[offset].g = 12;
266             c[offset].b = 12;
267             ++offset;
268         }
269 
270         /*16*/
271         if (kCGLARGB12121212Bit & cmodes) {
272             c[offset].a = 12;
273             c[offset].r = 12;
274             c[offset].g = 12;
275             c[offset].b = 12;
276             c[offset].is_argb = true;
277             ++offset;
278         }
279 
280         /*17*/
281         if (kCGLRGB161616Bit & cmodes) {
282             c[offset].r = 16;
283             c[offset].g = 16;
284             c[offset].b = 16;
285             ++offset;
286         }
287 
288         /*18*/
289         if (kCGLRGBA16161616Bit & cmodes) {
290             c[offset].r = 16;
291             c[offset].g = 16;
292             c[offset].b = 16;
293             c[offset].a = 16;
294             ++offset;
295         }
296     }
297     //#endif
298 
299     /* FIXME should we handle the floating point color modes, and if so, how? */
300 
301     return offset;
302 }
303 
304 static void
handleColorModes(struct glCapabilitiesConfig * c,GLint cmodes)305 handleColorModes(struct glCapabilitiesConfig *c, GLint cmodes)
306 {
307     c->total_color_buffers = handleColorAndAccumulation(c->color_buffers,
308                                                         cmodes, 0);
309 
310     assert(c->total_color_buffers < GLCAPS_COLOR_BUFFERS);
311 }
312 
313 static void
handleAccumulationModes(struct glCapabilitiesConfig * c,GLint cmodes)314 handleAccumulationModes(struct glCapabilitiesConfig *c, GLint cmodes)
315 {
316     c->total_accum_buffers = handleColorAndAccumulation(c->accum_buffers,
317                                                         cmodes, 1);
318     assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS);
319 }
320 
321 static void
handleDepthModes(struct glCapabilitiesConfig * c,GLint dmodes)322 handleDepthModes(struct glCapabilitiesConfig *c, GLint dmodes)
323 {
324     int offset = 0;
325 #define DEPTH(flag, value) do { \
326         if (dmodes & flag) { \
327             c->depth_buffers[offset++] = value; \
328         } \
329 } while (0)
330 
331     /*1*/
332     DEPTH(kCGL0Bit, 0);
333     /*2*/
334     DEPTH(kCGL1Bit, 1);
335     /*3*/
336     DEPTH(kCGL2Bit, 2);
337     /*4*/
338     DEPTH(kCGL3Bit, 3);
339     /*5*/
340     DEPTH(kCGL4Bit, 4);
341     /*6*/
342     DEPTH(kCGL5Bit, 5);
343     /*7*/
344     DEPTH(kCGL6Bit, 6);
345     /*8*/
346     DEPTH(kCGL8Bit, 8);
347     /*9*/
348     DEPTH(kCGL10Bit, 10);
349     /*10*/
350     DEPTH(kCGL12Bit, 12);
351     /*11*/
352     DEPTH(kCGL16Bit, 16);
353     /*12*/
354     DEPTH(kCGL24Bit, 24);
355     /*13*/
356     DEPTH(kCGL32Bit, 32);
357     /*14*/
358     DEPTH(kCGL48Bit, 48);
359     /*15*/
360     DEPTH(kCGL64Bit, 64);
361     /*16*/
362     DEPTH(kCGL96Bit, 96);
363     /*17*/
364     DEPTH(kCGL128Bit, 128);
365 
366 #undef DEPTH
367 
368     c->total_depth_buffer_depths = offset;
369     assert(c->total_depth_buffer_depths < GLCAPS_DEPTH_BUFFERS);
370 }
371 
372 /* Return non-zero if an error occurred. */
373 static CGLError
handleRendererDescriptions(CGLRendererInfoObj info,GLint r,struct glCapabilitiesConfig * c)374 handleRendererDescriptions(CGLRendererInfoObj info, GLint r,
375                            struct glCapabilitiesConfig *c)
376 {
377     CGLError err;
378     GLint accelerated = 0, flags = 0, aux = 0, samplebufs = 0, samples = 0;
379 
380     err = CGLDescribeRenderer(info, r, kCGLRPAccelerated, &accelerated);
381 
382     if (err)
383         return err;
384 
385     c->accelerated = accelerated;
386 
387     /* Buffering modes: single/double, stereo */
388     err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags);
389 
390     if (err)
391         return err;
392 
393     handleBufferModes(c, flags);
394 
395     /* AUX buffers */
396     err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux);
397 
398     if (err)
399         return err;
400 
401     c->aux_buffers = aux;
402 
403     /* Depth buffer size */
404     err = CGLDescribeRenderer(info, r, kCGLRPDepthModes, &flags);
405 
406     if (err)
407         return err;
408 
409     handleDepthModes(c, flags);
410 
411     /* Multisample buffers */
412     err = CGLDescribeRenderer(info, r, kCGLRPMaxSampleBuffers, &samplebufs);
413 
414     if (err)
415         return err;
416 
417     c->multisample_buffers = samplebufs;
418 
419     /* Multisample samples per multisample buffer */
420     err = CGLDescribeRenderer(info, r, kCGLRPMaxSamples, &samples);
421 
422     if (err)
423         return err;
424 
425     c->multisample_samples = samples;
426 
427     /* Stencil bit depths */
428     err = CGLDescribeRenderer(info, r, kCGLRPStencilModes, &flags);
429 
430     if (err)
431         return err;
432 
433     handleStencilModes(c, flags);
434 
435     /* Color modes (RGB/RGBA depths supported */
436     err = CGLDescribeRenderer(info, r, kCGLRPColorModes, &flags);
437 
438     if (err)
439         return err;
440 
441     handleColorModes(c, flags);
442 
443     err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags);
444 
445     if (err)
446         return err;
447 
448     handleAccumulationModes(c, flags);
449 
450     return kCGLNoError;
451 }
452 
453 static void
initCapabilities(struct glCapabilities * cap)454 initCapabilities(struct glCapabilities *cap)
455 {
456     cap->configurations = NULL;
457     cap->total_configurations = 0;
458 }
459 
460 static void
initConfig(struct glCapabilitiesConfig * c)461 initConfig(struct glCapabilitiesConfig *c)
462 {
463     int i;
464 
465     c->accelerated = false;
466     c->stereo = false;
467     c->aux_buffers = 0;
468     c->buffers = 0;
469 
470     c->total_depth_buffer_depths = 0;
471 
472     for (i = 0; i < GLCAPS_DEPTH_BUFFERS; ++i) {
473         c->depth_buffers[i] = GLCAPS_INVALID_DEPTH_VALUE;
474     }
475 
476     c->multisample_buffers = 0;
477     c->multisample_samples = 0;
478 
479     c->total_stencil_bit_depths = 0;
480 
481     for (i = 0; i < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS; ++i) {
482         c->stencil_bit_depths[i] = GLCAPS_INVALID_STENCIL_DEPTH;
483     }
484 
485     c->total_color_buffers = 0;
486 
487     for (i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
488         c->color_buffers[i].r = c->color_buffers[i].g =
489                                     c->color_buffers[i].b =
490                                         c->color_buffers[i].a =
491                                             GLCAPS_COLOR_BUF_INVALID_VALUE;
492         c->color_buffers[i].is_argb = false;
493     }
494 
495     c->total_accum_buffers = 0;
496 
497     for (i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
498         c->accum_buffers[i].r = c->accum_buffers[i].g =
499                                     c->accum_buffers[i].b =
500                                         c->accum_buffers[i].a =
501                                             GLCAPS_COLOR_BUF_INVALID_VALUE;
502         c->accum_buffers[i].is_argb = false;
503     }
504 
505     c->next = NULL;
506 }
507 
508 void
freeGlCapabilities(struct glCapabilities * cap)509 freeGlCapabilities(struct glCapabilities *cap)
510 {
511     struct glCapabilitiesConfig *conf, *next;
512 
513     conf = cap->configurations;
514 
515     while (conf) {
516         next = conf->next;
517         free(conf);
518         conf = next;
519     }
520 
521     cap->configurations = NULL;
522 }
523 
524 /* Return true if an error occurred. */
525 bool
getGlCapabilities(struct glCapabilities * cap)526 getGlCapabilities(struct glCapabilities *cap)
527 {
528     CGLRendererInfoObj info;
529     CGLError err;
530     GLint numRenderers = 0, r;
531 
532     initCapabilities(cap);
533 
534     err = CGLQueryRendererInfo((GLuint) - 1, &info, &numRenderers);
535     if (err) {
536         ErrorF("CGLQueryRendererInfo error: %s\n", CGLErrorString(err));
537         return err;
538     }
539 
540     for (r = 0; r < numRenderers; r++) {
541         struct glCapabilitiesConfig tmpconf, *conf;
542 
543         initConfig(&tmpconf);
544 
545         err = handleRendererDescriptions(info, r, &tmpconf);
546         if (err) {
547             ErrorF("handleRendererDescriptions returned error: %s\n",
548                    CGLErrorString(
549                        err));
550             ErrorF("trying to continue...\n");
551             continue;
552         }
553 
554         conf = malloc(sizeof(*conf));
555         if (NULL == conf) {
556             FatalError("Unable to allocate memory for OpenGL capabilities\n");
557         }
558 
559         /* Copy the struct. */
560         *conf = tmpconf;
561 
562         /* Now link the configuration into the list. */
563         conf->next = cap->configurations;
564         cap->configurations = conf;
565     }
566 
567     CGLDestroyRendererInfo(info);
568 
569     /* No error occurred.  We are done. */
570     return kCGLNoError;
571 }
572