capabilities.c (13602B)
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 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 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 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 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 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 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 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 454 initCapabilities(struct glCapabilities *cap) 455 { 456 cap->configurations = NULL; 457 cap->total_configurations = 0; 458 } 459 460 static void 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 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 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 }