From 21ea9d82aab8ff0e0d1904d188f96f9cfb2b051d Mon Sep 17 00:00:00 2001 From: George Peter Staplin Date: Fri, 24 Oct 2008 18:11:46 -0600 Subject: [PATCH] XQuartz: GL: Add feature detection of color sizes, and accum sizes. This gives us a *lot* more visuals, and they should be more accurate. Some of the visuals may have been wrong before. This may enable more OpenGL programs to behave correctly. I also suspect libGL needs a little work to handle some of these correctly. (cherry picked from commit 98a084ce9c455260ecdb5f8eecb67f33dbb53b69) --- hw/xquartz/GL/capabilities.c | 437 ++++++++++++++++++++++++++++++---- hw/xquartz/GL/capabilities.h | 29 ++- hw/xquartz/GL/indirect.c | 2 +- hw/xquartz/GL/visualConfigs.c | 165 ++++++++----- 4 files changed, 530 insertions(+), 103 deletions(-) diff --git a/hw/xquartz/GL/capabilities.c b/hw/xquartz/GL/capabilities.c index 479fc93e8..8101e49a5 100644 --- a/hw/xquartz/GL/capabilities.c +++ b/hw/xquartz/GL/capabilities.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,27 +31,371 @@ #include "capabilities.h" -//#define DIAGNOSTIC 0 - -static void handleBufferModes(struct glCapabilities *cap, GLint bufferModes) { +static void handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes) { if(bufferModes & kCGLStereoscopicBit) { - cap->stereo = true; + c->stereo = true; } if(bufferModes & kCGLDoubleBufferBit) { - cap->buffers = 2; + c->buffers = 2; } else { - cap->buffers = 1; + c->buffers = 1; } } -static void initCapabilities(struct glCapabilities *cap) { - cap->stereo = cap->buffers = cap->aux_buffers = 0; +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; } -enum { - MAX_DISPLAYS = 32 -}; +static int handleColorAndAccumulation(struct glColorBufCapabilities *c, + GLint cmodes) { + 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; + } + + /*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; + } + + /* 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); + + 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); + assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS); +} + +/* Return true if an error occured. */ +static CGLError handleRendererDescriptions(CGLRendererInfoObj info, GLint r, + struct glCapabilitiesConfig *c) { + CGLError err; + GLint accelerated = 0, flags = 0, aux = 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; + + + /* 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 true; + + handleColorModes(c, flags); + + err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags); + + if(err) + return true; + + handleAccumulationModes(c, flags); + + return 0; +} + +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->buffers = 0; + c->aux_buffers = 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; +} + +enum { MAX_DISPLAYS = 3 }; /*Return true if an error occured. */ bool getGlCapabilities(struct glCapabilities *cap) { @@ -63,9 +408,7 @@ bool getGlCapabilities(struct glCapabilities *cap) { err = CGGetActiveDisplayList(MAX_DISPLAYS, dspys, &displayCount); if(err) { -#ifdef DIAGNOSTIC - fprintf(stderr, "CGGetActiveDisplayList %s\n", CGLErrorString (err)); -#endif + fprintf(stderr, "CGGetActiveDisplayList error: %s\n", CGLErrorString(err)); return true; } @@ -73,36 +416,48 @@ bool getGlCapabilities(struct glCapabilities *cap) { displayMask = CGDisplayIDToOpenGLDisplayMask(dspys[i]); CGLRendererInfoObj info; - GLint numRenderers = 0, r, accelerated = 0, flags = 0, aux = 0; - - err = CGLQueryRendererInfo (displayMask, &info, &numRenderers); - if(!err) { - CGLDescribeRenderer (info, 0, kCGLRPRendererCount, &numRenderers); - for(r = 0; r < numRenderers; ++r) { - // find accelerated renderer (assume only one) - CGLDescribeRenderer (info, r, kCGLRPAccelerated, &accelerated); - if(accelerated) { - err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags); - if(err) { - CGLDestroyRendererInfo(info); - return true; - } + GLint numRenderers = 0, r, renderCount = 0; + + err = CGLQueryRendererInfo(displayMask, &info, &numRenderers); - handleBufferModes(cap, flags); - - err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux); - if(err) { - CGLDestroyRendererInfo(info); - return true; - } - - cap->aux_buffers = aux; - } - } - CGLDestroyRendererInfo(info); + if(err) { + fprintf(stderr, "CGLQueryRendererInfo error: %s\n", CGLErrorString(err)); + fprintf(stderr, "trying to continue...\n"); + continue; } - } + + CGLDescribeRenderer(info, 0, kCGLRPRendererCount, &renderCount); + for(r = 0; r < renderCount; ++r) { + CGLError derr; + struct glCapabilitiesConfig tmpconf, *conf; + + initConfig(&tmpconf); + + derr = handleRendererDescriptions(info, r, &tmpconf); + if(derr) { + fprintf(stderr, "error: %s\n", CGLErrorString(derr)); + 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 false; } diff --git a/hw/xquartz/GL/capabilities.h b/hw/xquartz/GL/capabilities.h index 6a026cfbb..20be30dce 100644 --- a/hw/xquartz/GL/capabilities.h +++ b/hw/xquartz/GL/capabilities.h @@ -25,13 +25,36 @@ #include -struct glCapabilities { - int stereo; +enum { GLCAPS_INVALID_STENCIL_DEPTH = -1 }; +enum { GLCAPS_COLOR_BUF_INVALID_VALUE = -1 }; +enum { GLCAPS_COLOR_BUFFERS = 20 }; +enum { GLCAPS_STENCIL_BIT_DEPTH_BUFFERS = 20 }; + +struct glColorBufCapabilities { + char r, g, b, a; + bool is_argb; +}; + +struct glCapabilitiesConfig { + bool accelerated; + bool stereo; int aux_buffers; int buffers; - /*TODO handle STENCIL and ACCUM*/ + int total_stencil_bit_depths; + char stencil_bit_depths[GLCAPS_STENCIL_BIT_DEPTH_BUFFERS]; + int total_color_buffers; + struct glColorBufCapabilities color_buffers[GLCAPS_COLOR_BUFFERS]; + int total_accum_buffers; + struct glColorBufCapabilities accum_buffers[GLCAPS_COLOR_BUFFERS]; + struct glCapabilitiesConfig *next; +}; + +struct glCapabilities { + struct glCapabilitiesConfig *configurations; + int total_configurations; }; bool getGlCapabilities(struct glCapabilities *cap); +void freeGlCapabilities(struct glCapabilities *cap); #endif diff --git a/hw/xquartz/GL/indirect.c b/hw/xquartz/GL/indirect.c index ed2204756..94ce10ce8 100644 --- a/hw/xquartz/GL/indirect.c +++ b/hw/xquartz/GL/indirect.c @@ -1157,7 +1157,7 @@ static __GLXscreen * __glXAquaScreenProbe(ScreenPtr pScreen) { init_screen_visuals(screen); - glAquaInitVisualConfigs(); + //glAquaInitVisualConfigs(); return &screen->base; } diff --git a/hw/xquartz/GL/visualConfigs.c b/hw/xquartz/GL/visualConfigs.c index a28754206..196989aca 100644 --- a/hw/xquartz/GL/visualConfigs.c +++ b/hw/xquartz/GL/visualConfigs.c @@ -61,37 +61,56 @@ void setVisualConfigs(void) { int numConfigs = 0; __GLXvisualConfig *visualConfigs = NULL; void **visualPrivates = NULL; - struct glCapabilities caps[1]; - int stereo, depth, aux, buffers, stencil, accum; + struct glCapabilities caps; + struct glCapabilitiesConfig *conf = NULL; + int stereo, depth, aux, buffers, stencil, accum, color; int i = 0; - - if(getGlCapabilities(caps)) { + + if(getGlCapabilities(&caps)) { ErrorF("error from getGlCapabilities()!\n"); return; } /* - caps->stereo is 0 or 1, but we need at least 1 iteration of the loop, so we treat - a true caps->stereo as 2. + conf->stereo is 0 or 1, but we need at least 1 iteration of the loop, + so we treat a true conf->stereo as 2. The depth size is 0 or 24. Thus we do 2 iterations for that. - caps->aux_buffers (when available/non-zero) result in 2 iterations instead of 1. + conf->aux_buffers (when available/non-zero) result in 2 iterations instead of 1. - caps->buffers indicates whether we have single or double buffering. + conf->buffers indicates whether we have single or double buffering. + + conf->total_stencil_bit_depths + + conf->total_color_buffers indicates the RGB/RGBA color depths. - 2 iterations for stencil (on and off (with a stencil size of 8)). - - 2 iterations for accum (on and off (with an accum color size of 16)). + conf->total_accum_buffers iterations for accum (with at least 1 if equal to 0) */ - numConfigs = (caps->stereo ? 2 : 1) * 2 * - (caps->aux_buffers ? 2 : 1) * (caps->buffers) * 2 * 2; + assert(NULL != caps.configurations); + conf = caps.configurations; + + numConfigs = 0; + + for(conf = caps.configurations; conf; conf = conf->next) { + if(conf->total_color_buffers <= 0) + continue; + + numConfigs += (conf->stereo ? 2 : 1) + * 2 /*depth*/ + * (conf->aux_buffers ? 2 : 1) + * conf->buffers + * ((conf->total_stencil_bit_depths > 0) ? conf->total_stencil_bit_depths : 1) + * conf->total_color_buffers + * ((conf->total_accum_buffers > 0) ? conf->total_accum_buffers : 1); + } visualConfigs = xcalloc(sizeof(*visualConfigs), numConfigs); if(NULL == visualConfigs) { ErrorF("xcalloc failure when allocating visualConfigs\n"); + freeGlCapabilities(&caps); return; } @@ -99,55 +118,83 @@ void setVisualConfigs(void) { if(NULL == visualPrivates) { ErrorF("xcalloc failure when allocating visualPrivates"); + freeGlCapabilities(&caps); xfree(visualConfigs); return; } - - + i = 0; /* current buffer */ - for (stereo = 0; stereo < (caps->stereo ? 2 : 1); ++stereo) { - for (depth = 0; depth < 2; ++depth) { - for (aux = 0; aux < (caps->aux_buffers ? 2 : 1); ++aux) { - for (buffers = 0; buffers < caps->buffers; ++buffers) { - for (stencil = 0; stencil < 2; ++stencil) { - for (accum = 0; accum < 2; ++accum) { - visualConfigs[i].vid = -1; - visualConfigs[i].class = -1; - visualConfigs[i].rgba = TRUE; - visualConfigs[i].redSize = -1; - visualConfigs[i].greenSize = -1; - visualConfigs[i].blueSize = -1; - visualConfigs[i].redMask = -1; - visualConfigs[i].greenMask = -1; - visualConfigs[i].blueMask = -1; - visualConfigs[i].alphaMask = 0; - if (accum) { - visualConfigs[i].accumRedSize = 16; - visualConfigs[i].accumGreenSize = 16; - visualConfigs[i].accumBlueSize = 16; - visualConfigs[i].accumAlphaSize = 16; - } else { - visualConfigs[i].accumRedSize = 0; - visualConfigs[i].accumGreenSize = 0; - visualConfigs[i].accumBlueSize = 0; - visualConfigs[i].accumAlphaSize = 0; + for(conf = caps.configurations; conf; conf = conf->next) { + for(stereo = 0; stereo < (conf->stereo ? 2 : 1); ++stereo) { + for(depth = 0; depth < 2; ++depth) { + for(aux = 0; aux < (conf->aux_buffers ? 2 : 1); ++aux) { + for(buffers = 0; buffers < conf->buffers; ++buffers) { + for(stencil = 0; stencil < ((conf->total_stencil_bit_depths > 0) ? + conf->total_stencil_bit_depths : 1); ++stencil) { + for(color = 0; color < conf->total_color_buffers; ++color) { + for(accum = 0; accum < ((conf->total_accum_buffers > 0) ? + conf->total_accum_buffers : 1); ++accum) { + visualConfigs[i].vid = -1; + visualConfigs[i].class = -1; + + visualConfigs[i].rgba = true; + visualConfigs[i].redSize = conf->color_buffers[color].r; + visualConfigs[i].greenSize = conf->color_buffers[color].g; + visualConfigs[i].blueSize = conf->color_buffers[color].b; + visualConfigs[i].alphaSize = conf->color_buffers[color].a; + + visualConfigs[i].redMask = -1; + visualConfigs[i].greenMask = -1; + visualConfigs[i].blueMask = -1; + visualConfigs[i].alphaMask = -1; + + if(conf->total_accum_buffers > 0) { + visualConfigs[i].accumRedSize = conf->accum_buffers[accum].r; + visualConfigs[i].accumGreenSize = conf->accum_buffers[accum].g; + visualConfigs[i].accumBlueSize = conf->accum_buffers[accum].b; + if(GLCAPS_COLOR_BUF_INVALID_VALUE != conf->accum_buffers[accum].a) { + visualConfigs[i].accumAlphaSize = conf->accum_buffers[accum].a; + } else { + visualConfigs[i].accumAlphaSize = 0; + } + } else { + visualConfigs[i].accumRedSize = 0; + visualConfigs[i].accumGreenSize = 0; + visualConfigs[i].accumBlueSize = 0; + visualConfigs[i].accumAlphaSize = 0; + } + + visualConfigs[i].doubleBuffer = buffers ? TRUE : FALSE; + visualConfigs[i].stereo = stereo ? TRUE : FALSE; + visualConfigs[i].bufferSize = -1; + + visualConfigs[i].depthSize = depth ? 24 : 0; + + if(conf->total_stencil_bit_depths > 0) { + visualConfigs[i].stencilSize = conf->stencil_bit_depths[stencil]; + } else { + visualConfigs[i].stencilSize = 0; + } + visualConfigs[i].auxBuffers = aux ? conf->aux_buffers : 0; + visualConfigs[i].level = 0; + visualConfigs[i].visualRating = GLX_NONE; + visualConfigs[i].transparentPixel = GLX_NONE; + visualConfigs[i].transparentRed = GLX_NONE; + visualConfigs[i].transparentGreen = GLX_NONE; + visualConfigs[i].transparentBlue = GLX_NONE; + visualConfigs[i].transparentAlpha = GLX_NONE; + visualConfigs[i].transparentIndex = GLX_NONE; + + /* + TODO possibly handle: + multiSampleSize; + nMultiSampleBuffers; + visualSelectGroup; + */ + + ++i; + } } - visualConfigs[i].doubleBuffer = buffers ? TRUE : FALSE; - visualConfigs[i].stereo = stereo ? TRUE : FALSE; - visualConfigs[i].bufferSize = -1; - - visualConfigs[i].depthSize = depth ? 24 : 0; - visualConfigs[i].stencilSize = stencil ? 8 : 0; - visualConfigs[i].auxBuffers = aux ? caps->aux_buffers : 0; - visualConfigs[i].level = 0; - visualConfigs[i].visualRating = GLX_NONE_EXT; - visualConfigs[i].transparentPixel = 0; - visualConfigs[i].transparentRed = 0; - visualConfigs[i].transparentGreen = 0; - visualConfigs[i].transparentBlue = 0; - visualConfigs[i].transparentAlpha = 0; - visualConfigs[i].transparentIndex = 0; - ++i; } } } @@ -156,9 +203,11 @@ void setVisualConfigs(void) { } if (i != numConfigs) { - ErrorF("numConfigs calculation error in setVisualConfigs!\n"); + ErrorF("numConfigs calculation error in setVisualConfigs! numConfigs is %d i is %d\n", numConfigs, i); abort(); } + freeGlCapabilities(&caps); + GlxSetVisualConfigs(numConfigs, visualConfigs, visualPrivates); }