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