egl_glx: Clean up the initialization code.

Proper detection of GLX extensions.  Convert fbconfigs or visuals in a
more unified way and validate the resulting configs.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
This commit is contained in:
Chia-I Wu 2009-10-01 18:16:10 +08:00 committed by Brian Paul
parent 326baecd75
commit 78c3a351bc

View file

@ -40,16 +40,14 @@
*/
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "dlfcn.h"
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <dlfcn.h>
#include "glxclient.h"
#include "eglconfigutil.h"
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
@ -58,46 +56,19 @@
#include "egllog.h"
#include "eglsurface.h"
#include <GL/gl.h>
#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
static const EGLint all_apis = (EGL_OPENGL_ES_BIT
| EGL_OPENGL_ES2_BIT
| EGL_OPENVG_BIT
/* | EGL_OPENGL_BIT */); /* can't do */
#ifndef GLX_VERSION_1_4
#error "GL/glx.h must be equal to or greater than GLX 1.4"
#endif
struct visual_attribs
{
/* X visual attribs */
int id;
int klass;
int depth;
int redMask, greenMask, blueMask;
int colormapSize;
int bitsPerRGB;
/*
* report OpenGL ES bits because apps usually forget to specify
* EGL_RENDERABLE_TYPE when choosing configs
*/
#define GLX_EGL_APIS (EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)
/* GL visual attribs */
int supportsGL;
int transparentType;
int transparentRedValue;
int transparentGreenValue;
int transparentBlueValue;
int transparentAlphaValue;
int transparentIndexValue;
int bufferSize;
int level;
int render_type;
int doubleBuffer;
int stereo;
int auxBuffers;
int redSize, greenSize, blueSize, alphaSize;
int depthSize;
int stencilSize;
int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
int numSamples, numMultisample;
int visualCaveat;
};
/** subclass of _EGLDriver */
struct GLX_egl_driver
@ -114,6 +85,21 @@ struct GLX_egl_display
GLXFBConfig *fbconfigs;
int glx_maj, glx_min;
const char *extensions;
EGLBoolean have_1_3;
EGLBoolean have_make_current_read;
EGLBoolean have_fbconfig;
EGLBoolean have_pbuffer;
/* GLX_SGIX_pbuffer */
PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX;
PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX;
/* workaround quirks of different GLX implementations */
EGLBoolean single_buffered_quirk;
EGLBoolean glx_window_quirk;
};
@ -139,6 +125,7 @@ struct GLX_egl_surface
struct GLX_egl_config
{
_EGLConfig Base; /**< base class */
EGLBoolean double_buffered;
int index;
};
@ -173,288 +160,369 @@ GLX_egl_config_index(_EGLConfig *conf)
return ((struct GLX_egl_config *) conf)->index;
}
static GLboolean
get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
struct visual_attribs *attribs)
{
const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
int rgba;
memset(attribs, 0, sizeof(struct visual_attribs));
#define MAP_ATTRIB(attr, memb) \
{ attr, offsetof(__GLcontextModes, memb) }
attribs->id = vInfo->visualid;
#if defined(__cplusplus) || defined(c_plusplus)
attribs->klass = vInfo->c_class;
#else
attribs->klass = vInfo->class;
#endif
attribs->depth = vInfo->depth;
attribs->redMask = vInfo->red_mask;
attribs->greenMask = vInfo->green_mask;
attribs->blueMask = vInfo->blue_mask;
attribs->colormapSize = vInfo->colormap_size;
attribs->bitsPerRGB = vInfo->bits_per_rgb;
if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
!attribs->supportsGL)
return GL_FALSE;
glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
if (!rgba)
return GL_FALSE;
attribs->render_type = GLX_RGBA_BIT;
glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
if (!attribs->doubleBuffer)
return GL_FALSE;
static const struct {
int attr;
int offset;
} fbconfig_attributes[] = {
/* table 3.1 of GLX 1.4 */
MAP_ATTRIB(GLX_FBCONFIG_ID, fbconfigID),
MAP_ATTRIB(GLX_BUFFER_SIZE, rgbBits),
MAP_ATTRIB(GLX_LEVEL, level),
MAP_ATTRIB(GLX_DOUBLEBUFFER, doubleBufferMode),
MAP_ATTRIB(GLX_STEREO, stereoMode),
MAP_ATTRIB(GLX_AUX_BUFFERS, numAuxBuffers),
MAP_ATTRIB(GLX_RED_SIZE, redBits),
MAP_ATTRIB(GLX_GREEN_SIZE, greenBits),
MAP_ATTRIB(GLX_BLUE_SIZE, blueBits),
MAP_ATTRIB(GLX_ALPHA_SIZE, alphaBits),
MAP_ATTRIB(GLX_DEPTH_SIZE, depthBits),
MAP_ATTRIB(GLX_STENCIL_SIZE, stencilBits),
MAP_ATTRIB(GLX_ACCUM_RED_SIZE, accumRedBits),
MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE, accumGreenBits),
MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE, accumBlueBits),
MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE, accumAlphaBits),
MAP_ATTRIB(GLX_SAMPLE_BUFFERS, sampleBuffers),
MAP_ATTRIB(GLX_SAMPLES, samples),
MAP_ATTRIB(GLX_RENDER_TYPE, renderType),
MAP_ATTRIB(GLX_DRAWABLE_TYPE, drawableType),
MAP_ATTRIB(GLX_X_RENDERABLE, xRenderable),
MAP_ATTRIB(GLX_X_VISUAL_TYPE, visualType),
MAP_ATTRIB(GLX_CONFIG_CAVEAT, visualRating),
MAP_ATTRIB(GLX_TRANSPARENT_TYPE, transparentPixel),
MAP_ATTRIB(GLX_TRANSPARENT_INDEX_VALUE, transparentIndex),
MAP_ATTRIB(GLX_TRANSPARENT_RED_VALUE, transparentRed),
MAP_ATTRIB(GLX_TRANSPARENT_GREEN_VALUE, transparentGreen),
MAP_ATTRIB(GLX_TRANSPARENT_BLUE_VALUE, transparentBlue),
MAP_ATTRIB(GLX_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
MAP_ATTRIB(GLX_MAX_PBUFFER_WIDTH, maxPbufferWidth),
MAP_ATTRIB(GLX_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
MAP_ATTRIB(GLX_MAX_PBUFFER_PIXELS, maxPbufferPixels),
MAP_ATTRIB(GLX_VISUAL_ID, visualID),
};
glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
/* get transparent pixel stuff */
glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
}
else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
}
/* multisample attribs */
#ifdef GLX_ARB_multisample
if (ext && strstr(ext, "GLX_ARB_multisample")) {
glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
}
#endif
else {
attribs->numSamples = 0;
attribs->numMultisample = 0;
}
#if defined(GLX_EXT_visual_rating)
if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
}
else {
attribs->visualCaveat = GLX_NONE_EXT;
}
#else
attribs->visualCaveat = 0;
#endif
return GL_TRUE;
}
#ifdef GLX_VERSION_1_3
static int
glx_token_to_visual_class(int visual_type)
{
switch (visual_type) {
case GLX_TRUE_COLOR:
return TrueColor;
case GLX_DIRECT_COLOR:
return DirectColor;
case GLX_PSEUDO_COLOR:
return PseudoColor;
case GLX_STATIC_COLOR:
return StaticColor;
case GLX_GRAY_SCALE:
return GrayScale;
case GLX_STATIC_GRAY:
return StaticGray;
case GLX_NONE:
default:
return None;
}
}
static int
get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig,
struct visual_attribs *attribs)
{
int visual_type;
int fbconfig_id;
memset(attribs, 0, sizeof(struct visual_attribs));
glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &fbconfig_id);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_VISUAL_ID, &attribs->id);
#if 0
attribs->depth = vInfo->depth;
attribs->redMask = vInfo->red_mask;
attribs->greenMask = vInfo->green_mask;
attribs->blueMask = vInfo->blue_mask;
attribs->colormapSize = vInfo->colormap_size;
attribs->bitsPerRGB = vInfo->bits_per_rgb;
#endif
glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type);
attribs->klass = glx_token_to_visual_class(visual_type);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type);
if (!(attribs->render_type & GLX_RGBA_BIT))
return 0;
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
if (!attribs->doubleBuffer)
return 0;
glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
/* get transparent pixel stuff */
glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
}
else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
}
glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
if (attribs->id == 0) {
attribs->id = fbconfig_id;
return EGL_PBUFFER_BIT | EGL_PIXMAP_BIT;
}
return EGL_WINDOW_BIT;
}
#endif
static EGLBoolean
create_configs(_EGLDisplay *disp, struct GLX_egl_display *GLX_dpy)
convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
struct GLX_egl_config *GLX_conf)
{
XVisualInfo theTemplate;
int numVisuals;
long mask;
int i;
struct visual_attribs attribs;
__GLcontextModes mode;
int err = 0, attr, val, i;
GLX_dpy->fbconfigs = NULL;
memset(&mode, 0, sizeof(mode));
#ifdef GLX_VERSION_1_3
/* get list of all fbconfigs on this screen */
GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, DefaultScreen(GLX_dpy->dpy), &numVisuals);
for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
int offset = fbconfig_attributes[i].offset;
attr = fbconfig_attributes[i].attr;
err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
if (err) {
if (err == GLX_BAD_ATTRIBUTE) {
err = 0;
continue;
}
break;
}
*((int *) ((char *) &mode + offset)) = val;
}
if (err)
return EGL_FALSE;
if (numVisuals == 0) {
GLX_dpy->fbconfigs = NULL;
goto xvisual;
/* must have rgba bit */
if (!(mode.renderType & GLX_RGBA_BIT))
return EGL_FALSE;
/* pixmap and pbuffer surfaces must be single-buffered in EGL */
if (mode.doubleBufferMode) {
mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT);
if (!mode.drawableType)
return EGL_FALSE;
}
for (i = 0; i < numVisuals; i++) {
struct GLX_egl_config *config;
int bit;
mode.rgbMode = GL_TRUE;
mode.haveAccumBuffer = (mode.accumRedBits +
mode.accumGreenBits +
mode.accumBlueBits +
mode.accumAlphaBits > 0);
mode.haveDepthBuffer = (mode.depthBits > 0);
mode.haveStencilBuffer = (mode.stencilBits > 0);
bit = get_fbconfig_attribs(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &attribs);
if (!bit)
continue;
GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
GLX_EGL_APIS, GLX_EGL_APIS);
}
config = CALLOC_STRUCT(GLX_egl_config);
config->index = i;
_eglInitConfig(&config->Base, (i+1));
SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE, bit);
static const struct {
int attr;
int offset;
} visual_attributes[] = {
/* table 3.7 of GLX 1.4 */
/* no GLX_USE_GL */
MAP_ATTRIB(GLX_BUFFER_SIZE, rgbBits),
MAP_ATTRIB(GLX_LEVEL, level),
MAP_ATTRIB(GLX_RGBA, rgbMode),
MAP_ATTRIB(GLX_DOUBLEBUFFER, doubleBufferMode),
MAP_ATTRIB(GLX_STEREO, stereoMode),
MAP_ATTRIB(GLX_AUX_BUFFERS, numAuxBuffers),
MAP_ATTRIB(GLX_RED_SIZE, redBits),
MAP_ATTRIB(GLX_GREEN_SIZE, greenBits),
MAP_ATTRIB(GLX_BLUE_SIZE, blueBits),
MAP_ATTRIB(GLX_ALPHA_SIZE, alphaBits),
MAP_ATTRIB(GLX_DEPTH_SIZE, depthBits),
MAP_ATTRIB(GLX_STENCIL_SIZE, stencilBits),
MAP_ATTRIB(GLX_ACCUM_RED_SIZE, accumRedBits),
MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE, accumGreenBits),
MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE, accumBlueBits),
MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE, accumAlphaBits),
MAP_ATTRIB(GLX_SAMPLE_BUFFERS, sampleBuffers),
MAP_ATTRIB(GLX_SAMPLES, samples),
MAP_ATTRIB(GLX_FBCONFIG_ID, fbconfigID),
/* GLX_EXT_visual_rating */
MAP_ATTRIB(GLX_VISUAL_CAVEAT_EXT, visualRating),
};
/* XXX possibly other things to init... */
_eglAddConfig(disp, &config->Base);
}
static int
get_visual_type(const XVisualInfo *vis)
{
int klass;
goto end;
#if defined(__cplusplus) || defined(c_plusplus)
klass = vis->c_class;
#else
klass = vis->class;
#endif
xvisual:
/* get list of all visuals on this screen */
theTemplate.screen = DefaultScreen(GLX_dpy->dpy);
mask = VisualScreenMask;
GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &theTemplate, &numVisuals);
switch (klass) {
case TrueColor:
return GLX_TRUE_COLOR;
case DirectColor:
return GLX_DIRECT_COLOR;
case PseudoColor:
return GLX_PSEUDO_COLOR;
case StaticColor:
return GLX_STATIC_COLOR;
case GrayScale:
return GLX_GRAY_SCALE;
case StaticGray:
return GLX_STATIC_GRAY;
default:
return GLX_NONE;
}
}
for (i = 0; i < numVisuals; i++) {
struct GLX_egl_config *config;
if (!get_visual_attribs(GLX_dpy->dpy, &GLX_dpy->visuals[i], &attribs))
continue;
static EGLBoolean
convert_visual(Display *dpy, XVisualInfo *vinfo,
struct GLX_egl_config *GLX_conf)
{
__GLcontextModes mode;
int err, attr, val, i;
config = CALLOC_STRUCT(GLX_egl_config);
/* the visual must support OpenGL */
err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
if (err || !val)
return EGL_FALSE;
config->index = i;
_eglInitConfig(&config->Base, (i+1));
SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE,
(EGL_WINDOW_BIT /*| EGL_PBUFFER_BIT | EGL_PIXMAP_BIT*/));
memset(&mode, 0, sizeof(mode));
/* XXX possibly other things to init... */
for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
int offset = visual_attributes[i].offset;
attr = visual_attributes[i].attr;
err = glXGetConfig(dpy, vinfo, attr, &val);
if (err) {
if (err == GLX_BAD_ATTRIBUTE) {
err = 0;
continue;
}
break;
}
*((int *) ((char *) &mode + offset)) = val;
}
if (err)
return EGL_FALSE;
_eglAddConfig(disp, &config->Base);
/* must be RGB mode */
if (!mode.rgbMode)
return EGL_FALSE;
mode.visualID = vinfo->visualid;
mode.visualType = get_visual_type(vinfo);
mode.redMask = vinfo->red_mask;
mode.greenMask = vinfo->green_mask;
mode.blueMask = vinfo->blue_mask;
mode.drawableType = GLX_WINDOW_BIT;
/* pixmap surfaces must be single-buffered in EGL */
if (!mode.doubleBufferMode)
mode.drawableType |= GLX_PIXMAP_BIT;
mode.renderType = GLX_RGBA_BIT;
mode.xRenderable = GL_TRUE;
mode.haveAccumBuffer = (mode.accumRedBits +
mode.accumGreenBits +
mode.accumBlueBits +
mode.accumAlphaBits > 0);
mode.haveDepthBuffer = (mode.depthBits > 0);
mode.haveStencilBuffer = (mode.stencilBits > 0);
GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
GLX_EGL_APIS, GLX_EGL_APIS);
}
static void
fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
{
_EGLConfig *conf = &GLX_conf->Base;
EGLint surface_type, r, g, b, a;
surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
/* some GLX impls do not like single-buffered window surface */
surface_type &= ~EGL_WINDOW_BIT;
/* pbuffer bit is usually not set */
if (GLX_dpy->have_pbuffer)
surface_type |= EGL_PBUFFER_BIT;
SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
}
/* no visual attribs unless window bit is set */
if (!(surface_type & EGL_WINDOW_BIT)) {
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
}
/* make sure buffer size is set correctly */
r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
}
static EGLBoolean
create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
EGLint screen)
{
EGLint num_configs = 0, i;
EGLint id = 1;
if (GLX_dpy->have_fbconfig) {
GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
}
else {
XVisualInfo vinfo_template;
long mask;
vinfo_template.screen = screen;
mask = VisualScreenMask;
GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
&num_configs);
}
if (!num_configs)
return EGL_FALSE;
for (i = 0; i < num_configs; i++) {
struct GLX_egl_config *GLX_conf, template;
EGLBoolean ok;
memset(&template, 0, sizeof(template));
_eglInitConfig(&template.Base, id);
if (GLX_dpy->have_fbconfig)
ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template);
else
ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template);
if (!ok)
continue;
fix_config(GLX_dpy, &template);
if (!_eglValidateConfig(&template.Base, EGL_FALSE)) {
_eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i);
continue;
}
GLX_conf = CALLOC_STRUCT(GLX_egl_config);
if (GLX_conf) {
memcpy(GLX_conf, &template, sizeof(template));
GLX_conf->index = i;
_eglAddConfig(dpy, &GLX_conf->Base);
id++;
}
}
end:
return EGL_TRUE;
}
static void
check_extensions(struct GLX_egl_display *GLX_dpy, EGLint screen)
{
GLX_dpy->extensions =
glXQueryExtensionsString(GLX_dpy->dpy, screen);
if (GLX_dpy->extensions) {
/* glXGetProcAddress is assumed */
if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) {
/* GLX 1.3 entry points are used */
GLX_dpy->have_make_current_read = EGL_TRUE;
}
if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) {
/* GLX 1.3 entry points are used */
GLX_dpy->have_fbconfig = EGL_TRUE;
}
if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) {
GLX_dpy->glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC)
glXGetProcAddress((const GLubyte *) "glXCreateGLXPbufferSGIX");
GLX_dpy->glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC)
glXGetProcAddress((const GLubyte *) "glXDestroyGLXPbufferSGIX");
if (GLX_dpy->glXCreateGLXPbufferSGIX &&
GLX_dpy->glXDestroyGLXPbufferSGIX &&
GLX_dpy->have_fbconfig)
GLX_dpy->have_pbuffer = EGL_TRUE;
}
}
if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) {
GLX_dpy->have_1_3 = EGL_TRUE;
GLX_dpy->have_make_current_read = EGL_TRUE;
GLX_dpy->have_fbconfig = EGL_TRUE;
GLX_dpy->have_pbuffer = EGL_TRUE;
}
}
static void
check_quirks(struct GLX_egl_display *GLX_dpy, EGLint screen)
{
const char *vendor;
GLX_dpy->single_buffered_quirk = EGL_TRUE;
GLX_dpy->glx_window_quirk = EGL_TRUE;
vendor = glXGetClientString(GLX_dpy->dpy, GLX_VENDOR);
if (vendor && strstr(vendor, "NVIDIA")) {
vendor = glXQueryServerString(GLX_dpy->dpy, screen, GLX_VENDOR);
if (vendor && strstr(vendor, "NVIDIA")) {
_eglLog(_EGL_DEBUG, "disable quirks");
GLX_dpy->single_buffered_quirk = EGL_FALSE;
GLX_dpy->glx_window_quirk = EGL_FALSE;
}
}
}
/**
* Called via eglInitialize(), GLX_drv->API.Initialize().
*/
@ -478,17 +546,33 @@ GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
}
}
disp->DriverData = (void *) GLX_dpy;
disp->ClientAPIsMask = all_apis;
if (!glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) {
_eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed");
if (!disp->NativeDisplay)
XCloseDisplay(GLX_dpy->dpy);
free(GLX_dpy);
return EGL_FALSE;
}
glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min);
check_extensions(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
check_quirks(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
create_configs(disp, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
if (!disp->NumConfigs) {
_eglLog(_EGL_WARNING, "GLX: failed to create any config");
if (!disp->NativeDisplay)
XCloseDisplay(GLX_dpy->dpy);
free(GLX_dpy);
return EGL_FALSE;
}
disp->DriverData = (void *) GLX_dpy;
disp->ClientAPIsMask = GLX_EGL_APIS;
/* we're supporting EGL 1.4 */
*major = 1;
*minor = 4;
create_configs(disp, GLX_dpy);
return EGL_TRUE;
}