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