/* * Copyright (c) 2008 Apple Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "capabilities.h" static void handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes) { if(bufferModes & kCGLStereoscopicBit) { c->stereo = true; } if(bufferModes & kCGLDoubleBufferBit) { c->buffers = 2; } else { c->buffers = 1; } } static void handleStencilModes(struct glCapabilitiesConfig *c, GLint smodes) { int offset = 0; if(kCGL0Bit & smodes) c->stencil_bit_depths[offset++] = 0; if(kCGL1Bit & smodes) c->stencil_bit_depths[offset++] = 1; if(kCGL2Bit & smodes) c->stencil_bit_depths[offset++] = 2; if(kCGL3Bit & smodes) c->stencil_bit_depths[offset++] = 3; if(kCGL4Bit & smodes) c->stencil_bit_depths[offset++] = 4; if(kCGL5Bit & smodes) c->stencil_bit_depths[offset++] = 5; if(kCGL6Bit & smodes) c->stencil_bit_depths[offset++] = 6; if(kCGL8Bit & smodes) c->stencil_bit_depths[offset++] = 8; if(kCGL10Bit & smodes) c->stencil_bit_depths[offset++] = 10; if(kCGL12Bit & smodes) c->stencil_bit_depths[offset++] = 12; if(kCGL16Bit & smodes) c->stencil_bit_depths[offset++] = 16; if(kCGL24Bit & smodes) c->stencil_bit_depths[offset++] = 24; if(kCGL32Bit & smodes) c->stencil_bit_depths[offset++] = 32; if(kCGL48Bit & smodes) c->stencil_bit_depths[offset++] = 48; if(kCGL64Bit & smodes) c->stencil_bit_depths[offset++] = 64; if(kCGL96Bit & smodes) c->stencil_bit_depths[offset++] = 96; if(kCGL128Bit & smodes) c->stencil_bit_depths[offset++] = 128; assert(offset < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS); c->total_stencil_bit_depths = offset; } static int handleColorAndAccumulation(struct glColorBufCapabilities *c, GLint cmodes, int forAccum) { int offset = 0; /*1*/ if(kCGLRGB444Bit & cmodes) { c[offset].r = 4; c[offset].g = 4; c[offset].b = 4; ++offset; } /*2*/ if(kCGLARGB4444Bit & cmodes) { c[offset].a = 4; c[offset].r = 4; c[offset].g = 4; c[offset].b = 4; c[offset].is_argb = true; ++offset; } /*3*/ if(kCGLRGB444A8Bit & cmodes) { c[offset].r = 4; c[offset].g = 4; c[offset].b = 4; c[offset].a = 8; ++offset; } /*4*/ if(kCGLRGB555Bit & cmodes) { c[offset].r = 5; c[offset].g = 5; c[offset].b = 5; ++offset; } /*5*/ if(kCGLARGB1555Bit & cmodes) { c[offset].a = 1; c[offset].r = 5; c[offset].g = 5; c[offset].b = 5; c[offset].is_argb = true; ++offset; } /*6*/ if(kCGLRGB555A8Bit & cmodes) { c[offset].r = 5; c[offset].g = 5; c[offset].b = 5; c[offset].a = 8; ++offset; } /*7*/ if(kCGLRGB565Bit & cmodes) { c[offset].r = 5; c[offset].g = 6; c[offset].b = 5; ++offset; } /*8*/ if(kCGLRGB565A8Bit & cmodes) { c[offset].r = 5; c[offset].g = 6; c[offset].b = 5; c[offset].a = 8; ++offset; } /*9*/ if(kCGLRGB888Bit & cmodes) { c[offset].r = 8; c[offset].g = 8; c[offset].b = 8; ++offset; } /*10*/ if(kCGLARGB8888Bit & cmodes) { c[offset].a = 8; c[offset].r = 8; c[offset].g = 8; c[offset].b = 8; c[offset].is_argb = true; ++offset; } /*11*/ if(kCGLRGB888A8Bit & cmodes) { c[offset].r = 8; c[offset].g = 8; c[offset].b = 8; c[offset].a = 8; ++offset; } if(forAccum) { //#if 0 /* FIXME * Disable this path, because some part of libGL, X, or Xplugin * doesn't work with sizes greater than 8. * When this is enabled and visuals are chosen using depths * such as 16, the result is that the windows don't redraw * and are often white, until a resize. */ /*12*/ if(kCGLRGB101010Bit & cmodes) { c[offset].r = 10; c[offset].g = 10; c[offset].b = 10; ++offset; } /*13*/ if(kCGLARGB2101010Bit & cmodes) { c[offset].a = 2; c[offset].r = 10; c[offset].g = 10; c[offset].b = 10; c[offset].is_argb = true; ++offset; } /*14*/ if(kCGLRGB101010_A8Bit & cmodes) { c[offset].r = 10; c[offset].g = 10; c[offset].b = 10; c[offset].a = 8; ++offset; } /*15*/ if(kCGLRGB121212Bit & cmodes) { c[offset].r = 12; c[offset].g = 12; c[offset].b = 12; ++offset; } /*16*/ if(kCGLARGB12121212Bit & cmodes) { c[offset].a = 12; c[offset].r = 12; c[offset].g = 12; c[offset].b = 12; c[offset].is_argb = true; ++offset; } /*17*/ if(kCGLRGB161616Bit & cmodes) { c[offset].r = 16; c[offset].g = 16; c[offset].b = 16; ++offset; } /*18*/ if(kCGLRGBA16161616Bit & cmodes) { c[offset].r = 16; c[offset].g = 16; c[offset].b = 16; c[offset].a = 16; ++offset; } } //#endif /* FIXME should we handle the floating point color modes, and if so, how? */ return offset; } static void handleColorModes(struct glCapabilitiesConfig *c, GLint cmodes) { c->total_color_buffers = handleColorAndAccumulation(c->color_buffers, cmodes, 0); assert(c->total_color_buffers < GLCAPS_COLOR_BUFFERS); } static void handleAccumulationModes(struct glCapabilitiesConfig *c, GLint cmodes) { c->total_accum_buffers = handleColorAndAccumulation(c->accum_buffers, cmodes, 1); assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS); } static void handleDepthModes(struct glCapabilitiesConfig *c, GLint dmodes) { int offset = 0; #define DEPTH(flag,value) do { \ if(dmodes & flag) { \ c->depth_buffers[offset++] = value; \ } \ } while(0) /*1*/ DEPTH(kCGL0Bit, 0); /*2*/ DEPTH(kCGL1Bit, 1); /*3*/ DEPTH(kCGL2Bit, 2); /*4*/ DEPTH(kCGL3Bit, 3); /*5*/ DEPTH(kCGL4Bit, 4); /*6*/ DEPTH(kCGL5Bit, 5); /*7*/ DEPTH(kCGL6Bit, 6); /*8*/ DEPTH(kCGL8Bit, 8); /*9*/ DEPTH(kCGL10Bit, 10); /*10*/ DEPTH(kCGL12Bit, 12); /*11*/ DEPTH(kCGL16Bit, 16); /*12*/ DEPTH(kCGL24Bit, 24); /*13*/ DEPTH(kCGL32Bit, 32); /*14*/ DEPTH(kCGL48Bit, 48); /*15*/ DEPTH(kCGL64Bit, 64); /*16*/ DEPTH(kCGL96Bit, 96); /*17*/ DEPTH(kCGL128Bit, 128); #undef DEPTH c->total_depth_buffer_depths = offset; assert(c->total_depth_buffer_depths < GLCAPS_DEPTH_BUFFERS); } /* Return non-zero if an error occured. */ static CGLError handleRendererDescriptions(CGLRendererInfoObj info, GLint r, struct glCapabilitiesConfig *c) { CGLError err; GLint accelerated = 0, flags = 0, aux = 0, samplebufs = 0, samples = 0; err = CGLDescribeRenderer (info, r, kCGLRPAccelerated, &accelerated); if(err) return err; c->accelerated = accelerated; /* Buffering modes: single/double, stereo */ err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags); if(err) return err; handleBufferModes(c, flags); /* AUX buffers */ err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux); if(err) return err; c->aux_buffers = aux; /* Depth buffer size */ err = CGLDescribeRenderer(info, r, kCGLRPDepthModes, &flags); if(err) return err; handleDepthModes(c, flags); /* Multisample buffers */ err = CGLDescribeRenderer(info, r, kCGLRPMaxSampleBuffers, &samplebufs); if(err) return err; c->multisample_buffers = samplebufs; /* Multisample samples per multisample buffer */ err = CGLDescribeRenderer(info, r, kCGLRPMaxSamples, &samples); if(err) return err; c->multisample_samples = samples; /* Stencil bit depths */ err = CGLDescribeRenderer(info, r, kCGLRPStencilModes, &flags); if(err) return err; handleStencilModes(c, flags); /* Color modes (RGB/RGBA depths supported */ err = CGLDescribeRenderer(info, r, kCGLRPColorModes, &flags); if(err) return err; handleColorModes(c, flags); err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags); if(err) return err; handleAccumulationModes(c, flags); return kCGLNoError; } static void initCapabilities(struct glCapabilities *cap) { cap->configurations = NULL; cap->total_configurations = 0; } static void initConfig(struct glCapabilitiesConfig *c) { int i; c->accelerated = false; c->stereo = false; c->aux_buffers = 0; c->buffers = 0; c->total_depth_buffer_depths = 0; for(i = 0; i < GLCAPS_DEPTH_BUFFERS; ++i) { c->depth_buffers[i] = GLCAPS_INVALID_DEPTH_VALUE; } c->multisample_buffers = 0; c->multisample_samples = 0; c->total_stencil_bit_depths = 0; for(i = 0; i < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS; ++i) { c->stencil_bit_depths[i] = GLCAPS_INVALID_STENCIL_DEPTH; } c->total_color_buffers = 0; for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) { c->color_buffers[i].r = c->color_buffers[i].g = c->color_buffers[i].b = c->color_buffers[i].a = GLCAPS_COLOR_BUF_INVALID_VALUE; c->color_buffers[i].is_argb = false; } c->total_accum_buffers = 0; for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) { c->accum_buffers[i].r = c->accum_buffers[i].g = c->accum_buffers[i].b = c->accum_buffers[i].a = GLCAPS_COLOR_BUF_INVALID_VALUE; c->accum_buffers[i].is_argb = false; } c->next = NULL; } void freeGlCapabilities(struct glCapabilities *cap) { struct glCapabilitiesConfig *conf, *next; conf = cap->configurations; while(conf) { next = conf->next; free(conf); conf = next; } cap->configurations = NULL; } /*Return true if an error occured. */ bool getGlCapabilities(struct glCapabilities *cap) { CGLRendererInfoObj info; CGLError err; GLint numRenderers = 0, r; initCapabilities(cap); err = CGLQueryRendererInfo((GLuint)-1, &info, &numRenderers); if(err) { fprintf(stderr, "CGLQueryRendererInfo error: %s\n", CGLErrorString(err)); return err; } for(r = 0; r < numRenderers; r++) { struct glCapabilitiesConfig tmpconf, *conf; initConfig(&tmpconf); err = handleRendererDescriptions(info, r, &tmpconf); if(err) { fprintf(stderr, "handleRendererDescriptions returned error: %s\n", CGLErrorString(err)); fprintf(stderr, "trying to continue...\n"); continue; } conf = malloc(sizeof(*conf)); if(NULL == conf) { perror("malloc"); abort(); } /* Copy the struct. */ *conf = tmpconf; /* Now link the configuration into the list. */ conf->next = cap->configurations; cap->configurations = conf; } CGLDestroyRendererInfo(info); /* No error occured. We are done. */ return kCGLNoError; }