diff options
author | Michal Krol <michal@vmware.com> | 2009-12-12 16:48:32 +0100 |
---|---|---|
committer | Michal Krol <michal@vmware.com> | 2009-12-12 16:48:32 +0100 |
commit | a3eb0f718e19653a2ad8e49396c904183be456f3 (patch) | |
tree | 0092574c469ea586a6cab8b8ebb7ac62b8221a2a /src/egl | |
parent | 491f384c3958067e6c4c994041f5d8d413b806bc (diff) | |
parent | 784cca9fa527de771754d76545970f78094b9adf (diff) |
Merge branch 'master' into glsl-pp-rework-2
Conflicts:
progs/perf/drawoverhead.c
progs/perf/teximage.c
progs/perf/vbo.c
progs/perf/vertexrate.c
src/mesa/shader/slang/library/slang_common_builtin_gc.h
Diffstat (limited to 'src/egl')
-rw-r--r-- | src/egl/drivers/demo/demo.c | 2 | ||||
-rw-r--r-- | src/egl/drivers/glx/egl_glx.c | 903 | ||||
-rw-r--r-- | src/egl/drivers/xdri/egl_xdri.c | 97 | ||||
-rw-r--r-- | src/egl/main/eglapi.c | 237 | ||||
-rw-r--r-- | src/egl/main/eglapi.h | 8 | ||||
-rw-r--r-- | src/egl/main/eglconfig.c | 939 | ||||
-rw-r--r-- | src/egl/main/eglconfig.h | 157 | ||||
-rw-r--r-- | src/egl/main/eglconfigutil.c | 77 | ||||
-rw-r--r-- | src/egl/main/eglconfigutil.h | 13 | ||||
-rw-r--r-- | src/egl/main/eglcontext.c | 40 | ||||
-rw-r--r-- | src/egl/main/eglcontext.h | 3 | ||||
-rw-r--r-- | src/egl/main/eglcurrent.c | 4 | ||||
-rw-r--r-- | src/egl/main/eglcurrent.h | 23 | ||||
-rw-r--r-- | src/egl/main/egldisplay.h | 1 | ||||
-rw-r--r-- | src/egl/main/egldriver.c | 159 | ||||
-rw-r--r-- | src/egl/main/eglglobals.c | 8 | ||||
-rw-r--r-- | src/egl/main/eglglobals.h | 3 | ||||
-rw-r--r-- | src/egl/main/egllog.c | 187 | ||||
-rw-r--r-- | src/egl/main/egllog.h | 11 | ||||
-rw-r--r-- | src/egl/main/eglmisc.c | 3 | ||||
-rw-r--r-- | src/egl/main/eglmisc.h | 2 | ||||
-rw-r--r-- | src/egl/main/eglsurface.c | 27 | ||||
-rw-r--r-- | src/egl/main/eglsurface.h | 2 |
23 files changed, 1917 insertions, 989 deletions
diff --git a/src/egl/drivers/demo/demo.c b/src/egl/drivers/demo/demo.c index aea4894448..0933c0bdaa 100644 --- a/src/egl/drivers/demo/demo.c +++ b/src/egl/drivers/demo/demo.c @@ -177,7 +177,7 @@ demoCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, Nat } } - if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) { + if (GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE) == 0) { _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface"); return NULL; } diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c index 4685f600e2..96292b0e9e 100644 --- a/src/egl/drivers/glx/egl_glx.c +++ b/src/egl/drivers/glx/egl_glx.c @@ -33,23 +33,12 @@ * Authors: Alan Hourihane <alanh@tungstengraphics.com> */ -/* - * TODO: - * - * test eglBind/ReleaseTexImage - */ - - -#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 "glxclient.h" +#include <GL/glx.h> +#include "eglconfigutil.h" #include "eglconfig.h" #include "eglcontext.h" #include "egldisplay.h" @@ -58,46 +47,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 + +/* + * 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) -struct visual_attribs -{ - /* X visual attribs */ - int id; - int klass; - int depth; - int redMask, greenMask, blueMask; - int colormapSize; - int bitsPerRGB; - - /* 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 +76,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; + }; @@ -131,7 +108,8 @@ struct GLX_egl_surface { _EGLSurface Base; /**< base class */ - GLXDrawable drawable; + Drawable drawable; + GLXDrawable glx_drawable; }; @@ -139,6 +117,7 @@ struct GLX_egl_surface struct GLX_egl_config { _EGLConfig Base; /**< base class */ + EGLBoolean double_buffered; int index; }; @@ -173,288 +152,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) } + + +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), +}; - 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; - - 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; +static EGLBoolean +convert_fbconfig(Display *dpy, GLXFBConfig fbconfig, + struct GLX_egl_config *GLX_conf) +{ + __GLcontextModes mode; + int err = 0, attr, val, i; + + memset(&mode, 0, sizeof(mode)); + + 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; } -#else - attribs->visualCaveat = 0; -#endif - - return GL_TRUE; -} + if (err) + return EGL_FALSE; -#ifdef GLX_VERSION_1_3 + /* must have rgba bit */ + if (!(mode.renderType & GLX_RGBA_BIT)) + return EGL_FALSE; -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; + /* 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; } + + 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); + + GLX_conf->double_buffered = (mode.doubleBufferMode != 0); + return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode, + GLX_EGL_APIS, GLX_EGL_APIS); } -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)); +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), +}; - glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &fbconfig_id); - glXGetFBConfigAttrib(dpy, fbconfig, GLX_VISUAL_ID, &attribs->id); +static int +get_visual_type(const XVisualInfo *vis) +{ + int klass; -#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; +#if defined(__cplusplus) || defined(c_plusplus) + klass = vis->c_class; +#else + klass = vis->class; #endif - glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type); - attribs->klass = glx_token_to_visual_class(visual_type); + 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; + } +} - 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; +static EGLBoolean +convert_visual(Display *dpy, XVisualInfo *vinfo, + struct GLX_egl_config *GLX_conf) +{ + __GLcontextModes mode; + int err, attr, val, i; - glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo); - glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers); + /* the visual must support OpenGL */ + err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val); + if (err || !val) + return EGL_FALSE; - 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); + memset(&mode, 0, sizeof(mode)); + + 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; - 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); + /* must be RGB mode */ + if (!mode.rgbMode) + return EGL_FALSE; - /* 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); - } + 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); +} - glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample); - glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples); - glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat); +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); + } - if (attribs->id == 0) { - attribs->id = fbconfig_id; - return EGL_PBUFFER_BIT | EGL_PIXMAP_BIT; + /* 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); } - return EGL_WINDOW_BIT; + /* 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); } -#endif static EGLBoolean -create_configs(_EGLDisplay *disp, struct GLX_egl_display *GLX_dpy) +create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy, + EGLint screen) { - XVisualInfo theTemplate; - int numVisuals; - long mask; - int i; - struct visual_attribs attribs; + EGLint num_configs = 0, i; + EGLint id = 1; - GLX_dpy->fbconfigs = NULL; - -#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); + if (GLX_dpy->have_fbconfig) { + GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs); + } + else { + XVisualInfo vinfo_template; + long mask; - if (numVisuals == 0) { - GLX_dpy->fbconfigs = NULL; - goto xvisual; + vinfo_template.screen = screen; + mask = VisualScreenMask; + GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template, + &num_configs); } - for (i = 0; i < numVisuals; i++) { - struct GLX_egl_config *config; - int bit; + if (!num_configs) + return EGL_FALSE; - bit = get_fbconfig_attribs(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &attribs); - if (!bit) + 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; + } - 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); - - /* XXX possibly other things to init... */ + GLX_conf = CALLOC_STRUCT(GLX_egl_config); + if (GLX_conf) { + memcpy(GLX_conf, &template, sizeof(template)); + GLX_conf->index = i; - _eglAddConfig(disp, &config->Base); + _eglAddConfig(dpy, &GLX_conf->Base); + id++; + } } - goto end; -#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); + return EGL_TRUE; +} - 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 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; + } - config = CALLOC_STRUCT(GLX_egl_config); + if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) { + /* GLX 1.3 entry points are used */ + GLX_dpy->have_fbconfig = EGL_TRUE; + } - 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*/)); + if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) { + GLX_dpy->glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC) + glXGetProcAddress((const GLubyte *) "glXCreateGLXPbufferSGIX"); + GLX_dpy->glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC) + glXGetProcAddress((const GLubyte *) "glXDestroyGLXPbufferSGIX"); - /* XXX possibly other things to init... */ + if (GLX_dpy->glXCreateGLXPbufferSGIX && + GLX_dpy->glXDestroyGLXPbufferSGIX && + GLX_dpy->have_fbconfig) + GLX_dpy->have_pbuffer = EGL_TRUE; + } + } - _eglAddConfig(disp, &config->Base); + 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; } +} -end: - return 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 +538,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; } @@ -539,8 +615,7 @@ GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, return NULL; } -#ifdef GLX_VERSION_1_3 - if (GLX_dpy->fbconfigs) + if (GLX_dpy->have_fbconfig) GLX_ctx->context = glXCreateNewContext(GLX_dpy->dpy, GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], @@ -548,7 +623,6 @@ GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, GLX_ctx_shared ? GLX_ctx_shared->context : NULL, GL_TRUE); else -#endif GLX_ctx->context = glXCreateContext(GLX_dpy->dpy, &GLX_dpy->visuals[GLX_egl_config_index(conf)], @@ -559,15 +633,6 @@ GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, return NULL; } -#if 1 - /* (maybe?) need to have a direct rendering context */ - if (!glXIsDirect(GLX_dpy->dpy, GLX_ctx->context)) { - glXDestroyContext(GLX_dpy->dpy, GLX_ctx->context); - free(GLX_ctx); - return NULL; - } -#endif - return &GLX_ctx->Base; } @@ -589,17 +654,14 @@ GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, if (!_eglMakeCurrent(drv, disp, dsurf, rsurf, ctx)) return EGL_FALSE; - ddraw = (GLX_dsurf) ? GLX_dsurf->drawable : None; - rdraw = (GLX_rsurf) ? GLX_rsurf->drawable : None; + ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None; + rdraw = (GLX_rsurf) ? GLX_rsurf->glx_drawable : None; cctx = (GLX_ctx) ? GLX_ctx->context : NULL; -#ifdef GLX_VERSION_1_3 - if (glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx)) - return EGL_TRUE; -#endif - - if (ddraw == rdraw && glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx)) - return EGL_TRUE; + if (GLX_dpy->have_make_current_read) + return glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx); + else if (ddraw == rdraw) + return glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx); return EGL_FALSE; } @@ -642,6 +704,20 @@ GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, } GLX_surf->drawable = window; + + if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk) + GLX_surf->glx_drawable = + glXCreateWindow(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_surf->drawable, NULL); + else + GLX_surf->glx_drawable = GLX_surf->drawable; + + if (!GLX_surf->glx_drawable) { + free(GLX_surf); + return NULL; + } + get_drawable_size(GLX_dpy->dpy, window, &width, &height); GLX_surf->Base.Width = width; GLX_surf->Base.Height = height; @@ -649,18 +725,13 @@ GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, return &GLX_surf->Base; } -#ifdef GLX_VERSION_1_3 static _EGLSurface * GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list) { struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); struct GLX_egl_surface *GLX_surf; - int i; - - /* GLX must >= 1.3 */ - if (!(GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3)) - return NULL; + uint width, height; GLX_surf = CALLOC_STRUCT(GLX_egl_surface); if (!GLX_surf) { @@ -674,25 +745,39 @@ GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, return NULL; } - for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { - switch (attrib_list[i]) { - /* no attribs at this time */ - default: - _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface"); - free(GLX_surf); - return NULL; + GLX_surf->drawable = pixmap; + + if (GLX_dpy->have_1_3) { + GLX_surf->glx_drawable = + glXCreatePixmap(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_surf->drawable, NULL); + } + else if (GLX_dpy->have_fbconfig) { + GLXFBConfig fbconfig = GLX_dpy->fbconfigs[GLX_egl_config_index(conf)]; + XVisualInfo *vinfo = glXGetVisualFromFBConfig(GLX_dpy->dpy, fbconfig); + if (vinfo) { + GLX_surf->glx_drawable = + glXCreateGLXPixmap(GLX_dpy->dpy, vinfo, GLX_surf->drawable); + XFree(vinfo); } } + else { + GLX_surf->glx_drawable = + glXCreateGLXPixmap(GLX_dpy->dpy, + &GLX_dpy->visuals[GLX_egl_config_index(conf)], + GLX_surf->drawable); + } - GLX_surf->drawable = - glXCreatePixmap(GLX_dpy->dpy, - GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], - pixmap, NULL); - if (!GLX_surf->drawable) { + if (!GLX_surf->glx_drawable) { free(GLX_surf); return NULL; } + get_drawable_size(GLX_dpy->dpy, pixmap, &width, &height); + GLX_surf->Base.Width = width; + GLX_surf->Base.Height = height; + return &GLX_surf->Base; } @@ -703,11 +788,7 @@ GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); struct GLX_egl_surface *GLX_surf; int attribs[5]; - int i = 0, j = 0; - - /* GLX must >= 1.3 */ - if (!(GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3)) - return NULL; + int i; GLX_surf = CALLOC_STRUCT(GLX_egl_surface); if (!GLX_surf) { @@ -721,33 +802,44 @@ GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, return NULL; } - while(attrib_list[i] != EGL_NONE) { - switch (attrib_list[i]) { - case EGL_WIDTH: - attribs[j++] = GLX_PBUFFER_WIDTH; - attribs[j++] = attrib_list[i+1]; - break; - case EGL_HEIGHT: - attribs[j++] = GLX_PBUFFER_HEIGHT; - attribs[j++] = attrib_list[i+1]; - break; + i = 0; + attribs[i] = None; + + GLX_surf->drawable = None; + + if (GLX_dpy->have_1_3) { + /* put geometry in attribs */ + if (GLX_surf->Base.Width) { + attribs[i++] = GLX_PBUFFER_WIDTH; + attribs[i++] = GLX_surf->Base.Width; + } + if (GLX_surf->Base.Height) { + attribs[i++] = GLX_PBUFFER_HEIGHT; + attribs[i++] = GLX_surf->Base.Height; } - i++; + attribs[i] = None; + + GLX_surf->glx_drawable = + glXCreatePbuffer(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + attribs); + } + else if (GLX_dpy->have_pbuffer) { + GLX_surf->glx_drawable = GLX_dpy->glXCreateGLXPbufferSGIX( + GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_surf->Base.Width, + GLX_surf->Base.Height, + attribs); } - attribs[j++] = 0; - GLX_surf->drawable = - glXCreatePbuffer(GLX_dpy->dpy, - GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], - attribs); - if (!GLX_surf->drawable) { + if (!GLX_surf->glx_drawable) { free(GLX_surf); return NULL; } return &GLX_surf->Base; } -#endif static EGLBoolean GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) @@ -755,15 +847,35 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); if (!_eglIsSurfaceBound(surf)) { struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); - switch (surf->Type) { - case EGL_PBUFFER_BIT: - glXDestroyPbuffer(GLX_dpy->dpy, GLX_surf->drawable); - break; - case EGL_PIXMAP_BIT: - glXDestroyPixmap(GLX_dpy->dpy, GLX_surf->drawable); - break; - default: - break; + + if (GLX_dpy->have_1_3) { + switch (surf->Type) { + case EGL_WINDOW_BIT: + if (!GLX_dpy->glx_window_quirk) + glXDestroyWindow(GLX_dpy->dpy, GLX_surf->glx_drawable); + break; + case EGL_PBUFFER_BIT: + glXDestroyPbuffer(GLX_dpy->dpy, GLX_surf->glx_drawable); + break; + case EGL_PIXMAP_BIT: + glXDestroyPixmap(GLX_dpy->dpy, GLX_surf->glx_drawable); + break; + default: + break; + } + } + else { + switch (surf->Type) { + case EGL_PBUFFER_BIT: + GLX_dpy->glXDestroyGLXPbufferSGIX(GLX_dpy->dpy, + GLX_surf->glx_drawable); + break; + case EGL_PIXMAP_BIT: + glXDestroyGLXPixmap(GLX_dpy->dpy, GLX_surf->glx_drawable); + break; + default: + break; + } } free(surf); } @@ -773,44 +885,12 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) static EGLBoolean -GLX_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, - EGLint buffer) -{ - struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); - struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); - - /* buffer ?? */ - glXBindTexImageEXT(GLX_dpy->dpy, GLX_surf->drawable, - GLX_FRONT_LEFT_EXT, NULL); - - return EGL_TRUE; -} - - -static EGLBoolean -GLX_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, - EGLint buffer) -{ - struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); - struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); - - /* buffer ?? */ - glXReleaseTexImageEXT(GLX_dpy->dpy, GLX_surf->drawable, - GLX_FRONT_LEFT_EXT); - - return EGL_TRUE; -} - - -static EGLBoolean GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw); - _eglLog(_EGL_DEBUG, "GLX: EGL SwapBuffers 0x%x",draw); - - glXSwapBuffers(GLX_dpy->dpy, GLX_surf->drawable); + glXSwapBuffers(GLX_dpy->dpy, GLX_surf->glx_drawable); return EGL_TRUE; } @@ -821,23 +901,24 @@ GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) static _EGLProc GLX_eglGetProcAddress(const char *procname) { - /* This is a bit of a hack to get at the gallium/Mesa state tracker - * function st_get_proc_address(). This will probably change at - * some point. - */ - _EGLProc (*get_proc_addr)(const char *procname); - _EGLProc proc_addr; - get_proc_addr = dlsym(NULL, "st_get_proc_address"); - if (get_proc_addr) - return get_proc_addr(procname); - - proc_addr = glXGetProcAddress((const GLubyte *)procname); - if (proc_addr) - return proc_addr; - - return (_EGLProc)dlsym(NULL, procname); + return (_EGLProc) glXGetProcAddress((const GLubyte *) procname); } +static EGLBoolean +GLX_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) +{ + glXWaitGL(); + return EGL_TRUE; +} + +static EGLBoolean +GLX_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) +{ + if (engine != EGL_CORE_NATIVE_ENGINE) + return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); + glXWaitX(); + return EGL_TRUE; +} static void GLX_Unload(_EGLDriver *drv) @@ -865,15 +946,13 @@ _eglMain(const char *args) GLX_drv->Base.API.CreateContext = GLX_eglCreateContext; GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent; GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface; -#ifdef GLX_VERSION_1_3 GLX_drv->Base.API.CreatePixmapSurface = GLX_eglCreatePixmapSurface; GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface; -#endif GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface; - GLX_drv->Base.API.BindTexImage = GLX_eglBindTexImage; - GLX_drv->Base.API.ReleaseTexImage = GLX_eglReleaseTexImage; GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers; GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress; + GLX_drv->Base.API.WaitClient = GLX_eglWaitClient; + GLX_drv->Base.API.WaitNative = GLX_eglWaitNative; GLX_drv->Base.Name = "GLX"; GLX_drv->Base.Unload = GLX_Unload; diff --git a/src/egl/drivers/xdri/egl_xdri.c b/src/egl/drivers/xdri/egl_xdri.c index 518091a2d1..d2affc66dd 100644 --- a/src/egl/drivers/xdri/egl_xdri.c +++ b/src/egl/drivers/xdri/egl_xdri.c @@ -48,6 +48,7 @@ #include "glapi/glapi.h" /* for glapi functions */ #include "eglconfig.h" +#include "eglconfigutil.h" #include "eglcontext.h" #include "egldisplay.h" #include "egldriver.h" @@ -104,6 +105,7 @@ struct xdri_egl_config _EGLConfig Base; /**< base class */ const __GLcontextModes *mode; /**< corresponding GLX mode */ + EGLint window_render_buffer; }; @@ -162,46 +164,76 @@ get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height) } +static EGLBoolean +convert_config(_EGLConfig *conf, EGLint id, const __GLcontextModes *m) +{ + static const EGLint all_apis = (EGL_OPENGL_ES_BIT | + EGL_OPENGL_ES2_BIT | + EGL_OPENVG_BIT | + EGL_OPENGL_BIT); + EGLint val; + + _eglInitConfig(conf, id); + if (!_eglConfigFromContextModesRec(conf, m, all_apis, all_apis)) + return EGL_FALSE; + + if (m->doubleBufferMode) { + /* pixmap and pbuffer surfaces are always single-buffered */ + val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); + val &= ~(EGL_PIXMAP_BIT | EGL_PBUFFER_BIT); + SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, val); + } + else { + /* EGL requires OpenGL ES context to be double-buffered */ + val = GET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE); + val &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT); + SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, val); + } + /* skip "empty" config */ + if (!val) + return EGL_FALSE; + + val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); + if (!(val & EGL_PBUFFER_BIT)) { + /* bind-to-texture cannot be EGL_TRUE without pbuffer bit */ + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE); + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE); + } + + /* EGL_NATIVE_RENDERABLE is a boolean */ + val = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE); + if (val != EGL_TRUE) + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_FALSE); + + return _eglValidateConfig(conf, EGL_FALSE); +} + + /** * Produce a set of EGL configs. */ static EGLint create_configs(_EGLDisplay *disp, const __GLcontextModes *m, EGLint first_id) { - static const EGLint all_apis = (EGL_OPENGL_ES_BIT | - EGL_OPENGL_ES2_BIT | - EGL_OPENVG_BIT | - EGL_OPENGL_BIT); int id = first_id; for (; m; m = m->next) { - /* add double buffered visual */ - if (m->doubleBufferMode) { - struct xdri_egl_config *config = CALLOC_STRUCT(xdri_egl_config); - - _eglInitConfig(&config->Base, id++); - - SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, m->rgbBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, m->redBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, m->greenBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, m->blueBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, m->alphaBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, m->depthBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, m->stencilBits); - SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, m->samples); - SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, m->sampleBuffers); - SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, m->visualID); - SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_TYPE, m->visualType); - 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); - - /* XXX possibly other things to init... */ - - /* Ptr from EGL config to GLcontextMode. Used in CreateContext(). */ - config->mode = m; - - _eglAddConfig(disp, &config->Base); + struct xdri_egl_config *xdri_conf; + _EGLConfig conf; + EGLint rb; + + if (!convert_config(&conf, id, m)) + continue; + + rb = (m->doubleBufferMode) ? EGL_BACK_BUFFER : EGL_SINGLE_BUFFER; + + xdri_conf = CALLOC_STRUCT(xdri_egl_config); + if (xdri_conf) { + memcpy(&xdri_conf->Base, &conf, sizeof(conf)); + xdri_conf->mode = m; + xdri_conf->window_render_buffer = rb; + _eglAddConfig(disp, &xdri_conf->Base); + id++; } } @@ -363,6 +395,9 @@ xdri_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, return NULL; } + /* the config decides the render buffer for the context */ + xdri_ctx->Base.WindowRenderBuffer = xdri_config->window_render_buffer; + xdri_ctx->driContext = psc->driScreen->createContext(psc, xdri_config->mode, diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 29617b7aff..14cc5fa613 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -9,12 +9,36 @@ * heterogeneous hardware devices in the future. * * The EGLDisplay, EGLConfig, EGLContext and EGLSurface types are - * opaque handles implemented with 32-bit unsigned integers. - * It's up to the driver function or fallback function to look up the - * handle and get an object. - * By using opaque handles, we leave open the possibility of having - * indirect rendering in the future, like GLX. + * opaque handles. Internal objects are linked to a display to + * create the handles. * + * For each public API entry point, the opaque handles are looked up + * before being dispatched to the drivers. When it fails to look up + * a handle, one of + * + * EGL_BAD_DISPLAY + * EGL_BAD_CONFIG + * EGL_BAD_CONTEXT + * EGL_BAD_SURFACE + * EGL_BAD_SCREEN_MESA + * EGL_BAD_MODE_MESA + * + * is generated and the driver function is not called. An + * uninitialized EGLDisplay has no driver associated with it. When + * such display is detected, + * + * EGL_NOT_INITIALIZED + * + * is generated. + * + * Some of the entry points use current display, context, or surface + * implicitly. For such entry points, the implicit objects are also + * checked before calling the driver function. Other than the + * errors listed above, + * + * EGL_BAD_CURRENT_SURFACE + * + * may also be generated. * * Notes on naming conventions: * @@ -92,8 +116,8 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) snprintf(disp->Version, sizeof(disp->Version), "%d.%d (%s)", major_int, minor_int, drv->Name); - /* update the global notion of supported APIs */ - _eglGlobal.ClientAPIsMask |= disp->ClientAPIsMask; + /* limit to APIs supported by core */ + disp->ClientAPIsMask &= _EGL_API_ALL_BITS; disp->Driver = drv; } else { @@ -496,15 +520,31 @@ eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) { + _EGLContext *ctx = _eglGetCurrentContext(); + _EGLSurface *surf; _EGL_DECLARE_DD(dpy); - return drv->API.SwapInterval(drv, disp, interval); + + if (!ctx || !_eglIsContextLinked(ctx) || ctx->Display != disp) + return _eglError(EGL_BAD_CONTEXT, __FUNCTION__); + + surf = ctx->DrawSurface; + if (!_eglIsSurfaceLinked(surf)) + return _eglError(EGL_BAD_SURFACE, __FUNCTION__); + + return drv->API.SwapInterval(drv, disp, surf, interval); } EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { + _EGLContext *ctx = _eglGetCurrentContext(); _EGL_DECLARE_DD_AND_SURFACE(dpy, surface); + + /* surface must be bound to current context in EGL 1.4 */ + if (!ctx || !_eglIsContextLinked(ctx) || surf != ctx->DrawSurface) + return _eglError(EGL_BAD_SURFACE, __FUNCTION__); + return drv->API.SwapBuffers(drv, disp, surf); } @@ -518,32 +558,66 @@ eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) EGLBoolean EGLAPIENTRY -eglWaitGL(void) +eglWaitClient(void) { - _EGLDisplay *disp = _eglGetCurrentDisplay(); + _EGLContext *ctx = _eglGetCurrentContext(); + _EGLDisplay *disp; _EGLDriver *drv; - if (!disp) + if (!ctx) return EGL_TRUE; + /* let bad current context imply bad current surface */ + if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface)) + return _eglError(EGL_BAD_CURRENT_SURFACE, __FUNCTION__); - /* a current display is always initialized */ + /* a valid current context implies an initialized current display */ + disp = ctx->Display; drv = disp->Driver; + assert(drv); - return drv->API.WaitGL(drv, disp); + return drv->API.WaitClient(drv, disp, ctx); +} + + +EGLBoolean EGLAPIENTRY +eglWaitGL(void) +{ +#ifdef EGL_VERSION_1_2 + _EGLThreadInfo *t = _eglGetCurrentThread(); + EGLint api_index = t->CurrentAPIIndex; + EGLint es_index = _eglConvertApiToIndex(EGL_OPENGL_ES_API); + EGLBoolean ret; + + if (api_index != es_index && _eglIsCurrentThreadDummy()) + return _eglError(EGL_BAD_ALLOC, "eglWaitGL"); + + t->CurrentAPIIndex = es_index; + ret = eglWaitClient(); + t->CurrentAPIIndex = api_index; + return ret; +#else + return eglWaitClient(); +#endif } EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { - _EGLDisplay *disp = _eglGetCurrentDisplay(); + _EGLContext *ctx = _eglGetCurrentContext(); + _EGLDisplay *disp; _EGLDriver *drv; - if (!disp) + if (!ctx) return EGL_TRUE; + /* let bad current context imply bad current surface */ + if (!_eglIsContextLinked(ctx) || !_eglIsSurfaceLinked(ctx->DrawSurface)) + return _eglError(EGL_BAD_CURRENT_SURFACE, __FUNCTION__); - /* a current display is always initialized */ + /* a valid current context implies an initialized current display */ + disp = ctx->Display; drv = disp->Driver; + assert(drv); return drv->API.WaitNative(drv, disp, engine); } @@ -568,8 +642,26 @@ eglGetCurrentContext(void) EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) { - _EGLSurface *s = _eglGetCurrentSurface(readdraw); - return _eglGetSurfaceHandle(s); + _EGLContext *ctx = _eglGetCurrentContext(); + _EGLSurface *surf; + + if (!ctx) + return EGL_NO_SURFACE; + + switch (readdraw) { + case EGL_DRAW: + surf = ctx->DrawSurface; + break; + case EGL_READ: + surf = ctx->ReadSurface; + break; + default: + _eglError(EGL_BAD_PARAMETER, __FUNCTION__); + surf = NULL; + break; + } + + return _eglGetSurfaceHandle(surf); } @@ -586,43 +678,11 @@ eglGetError(void) void (* EGLAPIENTRY eglGetProcAddress(const char *procname))() { - typedef void (*genericFunc)(); - struct name_function { + static const struct { const char *name; _EGLProc function; - }; - static struct name_function egl_functions[] = { - /* alphabetical order */ - { "eglBindTexImage", (_EGLProc) eglBindTexImage }, - { "eglChooseConfig", (_EGLProc) eglChooseConfig }, - { "eglCopyBuffers", (_EGLProc) eglCopyBuffers }, - { "eglCreateContext", (_EGLProc) eglCreateContext }, - { "eglCreatePbufferSurface", (_EGLProc) eglCreatePbufferSurface }, - { "eglCreatePixmapSurface", (_EGLProc) eglCreatePixmapSurface }, - { "eglCreateWindowSurface", (_EGLProc) eglCreateWindowSurface }, - { "eglDestroyContext", (_EGLProc) eglDestroyContext }, - { "eglDestroySurface", (_EGLProc) eglDestroySurface }, - { "eglGetConfigAttrib", (_EGLProc) eglGetConfigAttrib }, - { "eglGetConfigs", (_EGLProc) eglGetConfigs }, - { "eglGetCurrentContext", (_EGLProc) eglGetCurrentContext }, - { "eglGetCurrentDisplay", (_EGLProc) eglGetCurrentDisplay }, - { "eglGetCurrentSurface", (_EGLProc) eglGetCurrentSurface }, - { "eglGetDisplay", (_EGLProc) eglGetDisplay }, - { "eglGetError", (_EGLProc) eglGetError }, - { "eglGetProcAddress", (_EGLProc) eglGetProcAddress }, - { "eglInitialize", (_EGLProc) eglInitialize }, - { "eglMakeCurrent", (_EGLProc) eglMakeCurrent }, - { "eglQueryContext", (_EGLProc) eglQueryContext }, - { "eglQueryString", (_EGLProc) eglQueryString }, - { "eglQuerySurface", (_EGLProc) eglQuerySurface }, - { "eglReleaseTexImage", (_EGLProc) eglReleaseTexImage }, - { "eglSurfaceAttrib", (_EGLProc) eglSurfaceAttrib }, - { "eglSwapBuffers", (_EGLProc) eglSwapBuffers }, - { "eglSwapInterval", (_EGLProc) eglSwapInterval }, - { "eglTerminate", (_EGLProc) eglTerminate }, - { "eglWaitGL", (_EGLProc) eglWaitGL }, - { "eglWaitNative", (_EGLProc) eglWaitNative }, - /* Extensions */ + } egl_functions[] = { + /* extensions only */ #ifdef EGL_MESA_screen_surface { "eglChooseModeMESA", (_EGLProc) eglChooseModeMESA }, { "eglGetModesMESA", (_EGLProc) eglGetModesMESA }, @@ -637,22 +697,23 @@ void (* EGLAPIENTRY eglGetProcAddress(const char *procname))() { "eglQueryScreenModeMESA", (_EGLProc) eglQueryScreenModeMESA }, { "eglQueryModeStringMESA", (_EGLProc) eglQueryModeStringMESA }, #endif /* EGL_MESA_screen_surface */ -#ifdef EGL_VERSION_1_2 - { "eglBindAPI", (_EGLProc) eglBindAPI }, - { "eglCreatePbufferFromClientBuffer", (_EGLProc) eglCreatePbufferFromClientBuffer }, - { "eglQueryAPI", (_EGLProc) eglQueryAPI }, - { "eglReleaseThread", (_EGLProc) eglReleaseThread }, - { "eglWaitClient", (_EGLProc) eglWaitClient }, -#endif /* EGL_VERSION_1_2 */ { NULL, NULL } }; EGLint i; - for (i = 0; egl_functions[i].name; i++) { - if (strcmp(egl_functions[i].name, procname) == 0) { - return (genericFunc) egl_functions[i].function; + + if (!procname) + return NULL; + if (strncmp(procname, "egl", 3) == 0) { + for (i = 0; egl_functions[i].name; i++) { + if (strcmp(egl_functions[i].name, procname) == 0) + return egl_functions[i].function; } } + /* preload a driver if there isn't one */ + if (!_eglGlobal.NumDrivers) + _eglPreloadDriver(NULL); + /* now loop over drivers to query their procs */ for (i = 0; i < _eglGlobal.NumDrivers; i++) { _EGLProc p = _eglGlobal.Drivers[i]->API.GetProcAddress(procname); @@ -664,6 +725,9 @@ void (* EGLAPIENTRY eglGetProcAddress(const char *procname))() } +#ifdef EGL_MESA_screen_surface + + /* * EGL_MESA_screen extension */ @@ -838,6 +902,9 @@ eglQueryModeStringMESA(EGLDisplay dpy, EGLModeMESA mode) } +#endif /* EGL_MESA_screen_surface */ + + /** ** EGL 1.2 **/ @@ -867,33 +934,7 @@ eglBindAPI(EGLenum api) if (!_eglIsApiValid(api)) return _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); - switch (api) { -#ifdef EGL_VERSION_1_4 - case EGL_OPENGL_API: - if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_BIT) { - t->CurrentAPIIndex = _eglConvertApiToIndex(api); - return EGL_TRUE; - } - _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); - return EGL_FALSE; -#endif - case EGL_OPENGL_ES_API: - if (_eglGlobal.ClientAPIsMask & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)) { - t->CurrentAPIIndex = _eglConvertApiToIndex(api); - return EGL_TRUE; - } - _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); - return EGL_FALSE; - case EGL_OPENVG_API: - if (_eglGlobal.ClientAPIsMask & EGL_OPENVG_BIT) { - t->CurrentAPIIndex = _eglConvertApiToIndex(api); - return EGL_TRUE; - } - _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); - return EGL_FALSE; - default: - return EGL_FALSE; - } + t->CurrentAPIIndex = _eglConvertApiToIndex(api); return EGL_TRUE; } @@ -951,20 +992,4 @@ eglReleaseThread(void) } -EGLBoolean -eglWaitClient(void) -{ - _EGLDisplay *disp = _eglGetCurrentDisplay(); - _EGLDriver *drv; - - if (!disp) - return EGL_TRUE; - - /* a current display is always initialized */ - drv = disp->Driver; - - return drv->API.WaitClient(drv, disp); -} - - #endif /* EGL_VERSION_1_2 */ diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index 6081e58892..aa0abe3eb6 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -35,13 +35,13 @@ typedef EGLBoolean (*QuerySurface_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurf typedef EGLBoolean (*SurfaceAttrib_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint attribute, EGLint value); typedef EGLBoolean (*BindTexImage_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint buffer); typedef EGLBoolean (*ReleaseTexImage_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLint buffer); -typedef EGLBoolean (*SwapInterval_t)(_EGLDriver *drv, _EGLDisplay *dpy, EGLint interval); +typedef EGLBoolean (*SwapInterval_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval); typedef EGLBoolean (*SwapBuffers_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw); typedef EGLBoolean (*CopyBuffers_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, NativePixmapType target); /* misc funcs */ typedef const char *(*QueryString_t)(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name); -typedef EGLBoolean (*WaitGL_t)(_EGLDriver *drv, _EGLDisplay *dpy); +typedef EGLBoolean (*WaitClient_t)(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx); typedef EGLBoolean (*WaitNative_t)(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine); typedef _EGLProc (*GetProcAddress_t)(const char *procname); @@ -65,7 +65,6 @@ typedef const char * (*QueryModeStringMESA_t)(_EGLDriver *drv, _EGLDisplay *dpy, #ifdef EGL_VERSION_1_2 -typedef EGLBoolean (*WaitClient_t)(_EGLDriver *drv, _EGLDisplay *dpy); typedef _EGLSurface *(*CreatePbufferFromClientBuffer_t)(_EGLDriver *drv, _EGLDisplay *dpy, EGLenum buftype, EGLClientBuffer buffer, _EGLConfig *config, const EGLint *attrib_list); #endif /* EGL_VERSION_1_2 */ @@ -101,7 +100,7 @@ struct _egl_api CopyBuffers_t CopyBuffers; QueryString_t QueryString; - WaitGL_t WaitGL; + WaitClient_t WaitClient; WaitNative_t WaitNative; GetProcAddress_t GetProcAddress; @@ -120,7 +119,6 @@ struct _egl_api QueryModeStringMESA_t QueryModeStringMESA; #ifdef EGL_VERSION_1_2 - WaitClient_t WaitClient; CreatePbufferFromClientBuffer_t CreatePbufferFromClientBuffer; #endif }; diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index d47b99eed4..31d69a7708 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -15,302 +15,705 @@ #define MIN2(A, B) (((A) < (B)) ? (A) : (B)) - - -void -_eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val) -{ - assert(attr >= FIRST_ATTRIB); - assert(attr < FIRST_ATTRIB + MAX_ATTRIBS); - config->Attrib[attr - FIRST_ATTRIB] = val; -} +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /** * Init the given _EGLconfig to default values. * \param id the configuration's ID. + * + * Note that id must be positive for the config to be valid. + * It is also recommended that when there are N configs, their + * IDs are from 1 to N respectively. */ void _eglInitConfig(_EGLConfig *config, EGLint id) { memset(config, 0, sizeof(*config)); - config->Handle = (EGLConfig) _eglUIntToPointer((unsigned int) id); - _eglSetConfigAttrib(config, EGL_CONFIG_ID, id); - _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_CONFIG_CAVEAT, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_NATIVE_RENDERABLE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_TYPE, EGL_NONE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE); + + /* some attributes take non-zero default values */ + SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id); + SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_NONE); + SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE); + SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_NONE); #ifdef EGL_VERSION_1_2 - _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); - _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); + SET_CONFIG_ATTRIB(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); #endif /* EGL_VERSION_1_2 */ } /** - * Return the public handle for an internal _EGLConfig. - * This is the inverse of _eglLookupConfig(). + * Link a config to a display and return the handle of the link. + * The handle can be passed to client directly. + * + * Note that we just save the ptr to the config (we don't copy the config). */ EGLConfig -_eglGetConfigHandle(_EGLConfig *config) +_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf) { - return config ? config->Handle : 0; + _EGLConfig **configs; + + /* sanity check */ + assert(GET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID) > 0); + + configs = dpy->Configs; + if (dpy->NumConfigs >= dpy->MaxConfigs) { + EGLint new_size = dpy->MaxConfigs + 16; + assert(dpy->NumConfigs < new_size); + + configs = realloc(dpy->Configs, new_size * sizeof(dpy->Configs[0])); + if (!configs) + return (EGLConfig) NULL; + + dpy->Configs = configs; + dpy->MaxConfigs = new_size; + } + + conf->Display = dpy; + dpy->Configs[dpy->NumConfigs++] = conf; + + return (EGLConfig) conf; } -/** - * Given an EGLConfig handle, return the corresponding _EGLConfig object. - * This is the inverse of _eglGetConfigHandle(). - */ -_EGLConfig * -_eglLookupConfig(EGLConfig config, _EGLDisplay *disp) +#ifndef _EGL_SKIP_HANDLE_CHECK + + +EGLBoolean +_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy) { + EGLint num_configs = (dpy) ? dpy->NumConfigs : 0; EGLint i; - for (i = 0; i < disp->NumConfigs; i++) { - if (disp->Configs[i]->Handle == config) { - return disp->Configs[i]; + + for (i = 0; i < num_configs; i++) { + _EGLConfig *conf = dpy->Configs[i]; + if (conf == (_EGLConfig *) config) { + assert(conf->Display == dpy); + break; } } - return NULL; + return (i < num_configs); } -/** - * Add the given _EGLConfig to the given display. - * Note that we just save the ptr to the config (we don't copy the config). - */ -_EGLConfig * -_eglAddConfig(_EGLDisplay *display, _EGLConfig *config) +#endif /* _EGL_SKIP_HANDLE_CHECK */ + + +enum { + /* types */ + ATTRIB_TYPE_INTEGER, + ATTRIB_TYPE_BOOLEAN, + ATTRIB_TYPE_BITMASK, + ATTRIB_TYPE_ENUM, + ATTRIB_TYPE_PSEUDO, /* non-queryable */ + ATTRIB_TYPE_PLATFORM, /* platform-dependent */ + /* criteria */ + ATTRIB_CRITERION_EXACT, + ATTRIB_CRITERION_ATLEAST, + ATTRIB_CRITERION_MASK, + ATTRIB_CRITERION_SPECIAL, + ATTRIB_CRITERION_IGNORE, +}; + + +/* EGL spec Table 3.1 and 3.4 */ +static const struct { + EGLint attr; + EGLint type; + EGLint criterion; + EGLint default_value; +} _eglValidationTable[] = { - _EGLConfig **newConfigs; - EGLint n; - - /* do some sanity checks on the config's attribs */ - assert(GET_CONFIG_ATTRIB(config, EGL_CONFIG_ID) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE) != 0x0); - assert(GET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE) != 0x0); - assert(GET_CONFIG_ATTRIB(config, EGL_RED_SIZE) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE) > 0); - - n = display->NumConfigs; - - /* realloc array of ptrs */ - newConfigs = (_EGLConfig **) realloc(display->Configs, - (n + 1) * sizeof(_EGLConfig *)); - if (newConfigs) { - display->Configs = newConfigs; - display->Configs[n] = config; - display->NumConfigs++; - return config; - } - else { - return NULL; - } -} + { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_RGB_BUFFER }, + { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + 0 }, + { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_EXACT, + 0 }, + { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + EGL_OPENGL_ES_BIT }, + { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + EGL_WINDOW_BIT }, + { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_NONE }, + { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + /* these are not real attributes */ + { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, + ATTRIB_CRITERION_SPECIAL, + EGL_NONE }, + { EGL_PRESERVED_RESOURCES, ATTRIB_TYPE_PSEUDO, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_NONE, ATTRIB_TYPE_PSEUDO, + ATTRIB_CRITERION_IGNORE, + 0 } +}; /** - * Parse the attrib_list to fill in the fields of the given _eglConfig - * Return EGL_FALSE if any errors, EGL_TRUE otherwise. + * Return true if a config is valid. When for_matching is true, + * EGL_DONT_CARE is accepted as a valid attribute value, and checks + * for conflicting attribute values are skipped. + * + * Note that some attributes are platform-dependent and are not + * checked. */ EGLBoolean -_eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list) +_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) { - EGLint i; - - /* set all config attribs to EGL_DONT_CARE */ - for (i = 0; i < MAX_ATTRIBS; i++) { - config->Attrib[i] = EGL_DONT_CARE; - } - - /* by default choose windows unless otherwise specified */ - config->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] = EGL_WINDOW_BIT; - - for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { - const EGLint attr = attrib_list[i]; - if (attr >= EGL_BUFFER_SIZE && - attr <= EGL_MAX_SWAP_INTERVAL) { - EGLint k = attr - FIRST_ATTRIB; - assert(k >= 0); - assert(k < MAX_ATTRIBS); - config->Attrib[k] = attrib_list[++i]; - } -#ifdef EGL_VERSION_1_2 - else if (attr == EGL_COLOR_BUFFER_TYPE) { - EGLint bufType = attrib_list[++i]; - if (bufType != EGL_RGB_BUFFER && bufType != EGL_LUMINANCE_BUFFER) { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + EGLint i, attr, val; + EGLBoolean valid = EGL_TRUE; + EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0; + EGLint alpha_size = 0, buffer_size = 0; + + /* all attributes should have been listed */ + assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS); + + /* check attributes by their types */ + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + EGLint mask; + + attr = _eglValidationTable[i].attr; + val = GET_CONFIG_ATTRIB(conf, attr); + + switch (_eglValidationTable[i].type) { + case ATTRIB_TYPE_INTEGER: + switch (attr) { + case EGL_CONFIG_ID: + /* config id must be positive */ + if (val <= 0) + valid = EGL_FALSE; + break; + case EGL_SAMPLE_BUFFERS: + /* there can be at most 1 sample buffer */ + if (val > 1) + valid = EGL_FALSE; + break; + case EGL_RED_SIZE: + red_size = val; + break; + case EGL_GREEN_SIZE: + green_size = val; + break; + case EGL_BLUE_SIZE: + blue_size = val; + break; + case EGL_LUMINANCE_SIZE: + luminance_size = val; + break; + case EGL_ALPHA_SIZE: + alpha_size = val; + break; + case EGL_BUFFER_SIZE: + buffer_size = val; + break; } - _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, bufType); - } - else if (attr == EGL_RENDERABLE_TYPE) { - EGLint renType = attrib_list[++i]; - if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENVG_BIT)) { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + if (val < 0) + valid = EGL_FALSE; + break; + case ATTRIB_TYPE_BOOLEAN: + if (val != EGL_TRUE && val != EGL_FALSE) + valid = EGL_FALSE; + break; + case ATTRIB_TYPE_ENUM: + switch (attr) { + case EGL_CONFIG_CAVEAT: + if (val != EGL_NONE && val != EGL_SLOW_CONFIG && + val != EGL_NON_CONFORMANT_CONFIG) + valid = EGL_FALSE; + break; + case EGL_TRANSPARENT_TYPE: + if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) + valid = EGL_FALSE; + break; + case EGL_COLOR_BUFFER_TYPE: + if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) + valid = EGL_FALSE; + break; + default: + assert(0); + break; } - _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, renType); - } - else if (attr == EGL_ALPHA_MASK_SIZE || - attr == EGL_LUMINANCE_SIZE) { - EGLint value = attrib_list[++i]; - _eglSetConfigAttrib(config, attr, value); + break; + case ATTRIB_TYPE_BITMASK: + switch (attr) { + case EGL_SURFACE_TYPE: + mask = EGL_PBUFFER_BIT | + EGL_PIXMAP_BIT | + EGL_WINDOW_BIT | + EGL_VG_COLORSPACE_LINEAR_BIT | + EGL_VG_ALPHA_FORMAT_PRE_BIT | + EGL_MULTISAMPLE_RESOLVE_BOX_BIT | + EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + break; + case EGL_RENDERABLE_TYPE: + case EGL_CONFORMANT: + mask = EGL_OPENGL_ES_BIT | + EGL_OPENVG_BIT | + EGL_OPENGL_ES2_BIT | + EGL_OPENGL_BIT; + break; + default: + assert(0); + break; + } + if (val & ~mask) + valid = EGL_FALSE; + break; + case ATTRIB_TYPE_PLATFORM: + /* unable to check platform-dependent attributes here */ + break; + case ATTRIB_TYPE_PSEUDO: + /* pseudo attributes should not be set */ + if (val != 0) + valid = EGL_FALSE; + break; + default: + assert(0); + break; } -#endif /* EGL_VERSION_1_2 */ - else { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + + if (!valid && for_matching) { + /* accept EGL_DONT_CARE as a valid value */ + if (val == EGL_DONT_CARE) + valid = EGL_TRUE; + if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) + valid = EGL_TRUE; } + if (!valid) + break; } - return EGL_TRUE; -} + /* any invalid attribute value should have been catched */ + if (!valid || for_matching) + return valid; + + /* now check for conflicting attribute values */ + + switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) { + case EGL_RGB_BUFFER: + if (luminance_size) + valid = EGL_FALSE; + if (red_size + green_size + blue_size + alpha_size != buffer_size) + valid = EGL_FALSE; + break; + case EGL_LUMINANCE_BUFFER: + if (red_size || green_size || blue_size) + valid = EGL_FALSE; + if (luminance_size + alpha_size != buffer_size) + valid = EGL_FALSE; + break; + } -#define EXACT 1 -#define ATLEAST 2 -#define MASK 3 -#define SMALLER 4 -#define SPECIAL 5 -#define NONE 6 + val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS); + if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES)) + valid = EGL_FALSE; + + val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); + if (!(val & EGL_WINDOW_BIT)) { + if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 || + GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE) + valid = EGL_FALSE; + } + if (!(val & EGL_PBUFFER_BIT)) { + if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) || + GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA)) + valid = EGL_FALSE; + } + + return valid; +} -struct sort_info { - EGLint Attribute; - EGLint MatchCriteria; - EGLint SortOrder; -}; -/* This encodes the info from Table 3.5 of the EGL spec, ordered by - * Sort Priority. +/** + * Return true if a config matches the criteria. This and + * _eglParseConfigAttribList together implement the algorithm + * described in "Selection of EGLConfigs". * - * XXX To do: EGL 1.2 attribs + * Note that attributes that are special (currently, only + * EGL_MATCH_NATIVE_PIXMAP) are ignored. */ -static struct sort_info SortInfo[] = { - { EGL_CONFIG_CAVEAT, EXACT, SPECIAL }, - { EGL_RED_SIZE, ATLEAST, SPECIAL }, - { EGL_GREEN_SIZE, ATLEAST, SPECIAL }, - { EGL_BLUE_SIZE, ATLEAST, SPECIAL }, - { EGL_ALPHA_SIZE, ATLEAST, SPECIAL }, - { EGL_BUFFER_SIZE, ATLEAST, SMALLER }, - { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER }, - { EGL_SAMPLES, ATLEAST, SMALLER }, - { EGL_DEPTH_SIZE, ATLEAST, SMALLER }, - { EGL_STENCIL_SIZE, ATLEAST, SMALLER }, - { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL }, - { EGL_CONFIG_ID, EXACT, SMALLER }, - { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE }, - { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE }, - { EGL_LEVEL, EXACT, NONE }, - { EGL_NATIVE_RENDERABLE, EXACT, NONE }, - { EGL_MAX_SWAP_INTERVAL, EXACT, NONE }, - { EGL_MIN_SWAP_INTERVAL, EXACT, NONE }, - { EGL_SURFACE_TYPE, MASK, NONE }, - { EGL_TRANSPARENT_TYPE, EXACT, NONE }, - { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE }, - { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE }, - { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE }, - { 0, 0, 0 } -}; +EGLBoolean +_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) +{ + EGLint attr, val, i; + EGLBoolean matched = EGL_TRUE; + + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + EGLint cmp; + if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) + continue; + + attr = _eglValidationTable[i].attr; + cmp = GET_CONFIG_ATTRIB(criteria, attr); + if (cmp == EGL_DONT_CARE) + continue; + + val = GET_CONFIG_ATTRIB(conf, attr); + switch (_eglValidationTable[i].criterion) { + case ATTRIB_CRITERION_EXACT: + if (val != cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_ATLEAST: + if (val < cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_MASK: + if ((val & cmp) != cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_SPECIAL: + /* ignored here */ + break; + default: + assert(0); + break; + } + + if (!matched) + break; + } + + return matched; +} /** - * Return EGL_TRUE if the attributes of c meet or exceed the minimums - * specified by min. + * Initialize a criteria config from the given attribute list. + * Return EGL_FALSE if any of the attribute is invalid. */ -static EGLBoolean -_eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min) +EGLBoolean +_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list) { - EGLint i; - for (i = 0; SortInfo[i].Attribute != 0; i++) { - const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute); - if (mv != EGL_DONT_CARE) { - const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute); - if (SortInfo[i].MatchCriteria == EXACT) { - if (cv != mv) { - return EGL_FALSE; - } - } - else if (SortInfo[i].MatchCriteria == ATLEAST) { - if (cv < mv) { - return EGL_FALSE; - } - } - else { - assert(SortInfo[i].MatchCriteria == MASK); - if ((mv & cv) != mv) { - return EGL_FALSE; - } + EGLint attr, val, i; + EGLint config_id = 0, level = 0; + EGLBoolean has_native_visual_type = EGL_FALSE; + EGLBoolean has_transparent_color = EGL_FALSE; + + /* reset to default values */ + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + attr = _eglValidationTable[i].attr; + val = _eglValidationTable[i].default_value; + SET_CONFIG_ATTRIB(conf, attr, val); + } + + /* parse the list */ + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { + EGLint idx; + + attr = attrib_list[i]; + val = attrib_list[i + 1]; + + idx = _eglIndexConfig(conf, attr); + if (idx < 0) + return EGL_FALSE; + conf->Storage[idx] = val; + + /* rememeber some attributes for post-processing */ + switch (attr) { + case EGL_CONFIG_ID: + config_id = val; + break; + case EGL_LEVEL: + level = val; + break; + case EGL_NATIVE_VISUAL_TYPE: + has_native_visual_type = EGL_TRUE; + break; + case EGL_TRANSPARENT_RED_VALUE: + case EGL_TRANSPARENT_GREEN_VALUE: + case EGL_TRANSPARENT_BLUE_VALUE: + has_transparent_color = EGL_TRUE; + break; + default: + break; + } + } + + if (!_eglValidateConfig(conf, EGL_TRUE)) + return EGL_FALSE; + + /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ + if (level == EGL_DONT_CARE) + return EGL_FALSE; + + /* ignore other attributes when EGL_CONFIG_ID is given */ + if (config_id > 0) { + _eglResetConfigKeys(conf, EGL_DONT_CARE); + SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id); + } + else { + if (has_native_visual_type) { + val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); + if (!(val & EGL_WINDOW_BIT)) + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE); + } + + if (has_transparent_color) { + val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE); + if (val == EGL_NONE) { + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, + EGL_DONT_CARE); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, + EGL_DONT_CARE); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, + EGL_DONT_CARE); } } } + return EGL_TRUE; } /** - * Compare configs 'a' and 'b' and return -1 if a belongs before b, - * 1 if a belongs after b, or 0 if they're equal. - * Used by qsort(). + * Decide the ordering of conf1 and conf2, under the given criteria. + * When compare_id is true, this implements the algorithm described + * in "Sorting of EGLConfigs". When compare_id is false, + * EGL_CONFIG_ID is not compared. + * + * It returns a negative integer if conf1 is considered to come + * before conf2; a positive integer if conf2 is considered to come + * before conf1; zero if the ordering cannot be decided. + * + * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is + * ignored here. */ -static int -_eglCompareConfigs(const void *a, const void *b) +EGLint +_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, + const _EGLConfig *criteria, EGLBoolean compare_id) { - const _EGLConfig *aConfig = (const _EGLConfig *) a; - const _EGLConfig *bConfig = (const _EGLConfig *) b; + const EGLint compare_attribs[] = { + EGL_BUFFER_SIZE, + EGL_SAMPLE_BUFFERS, + EGL_SAMPLES, + EGL_DEPTH_SIZE, + EGL_STENCIL_SIZE, + EGL_ALPHA_MASK_SIZE, + }; + EGLint val1, val2; + EGLBoolean rgb_buffer; EGLint i; - for (i = 0; SortInfo[i].Attribute != 0; i++) { - const EGLint aVal = GET_CONFIG_ATTRIB(aConfig, SortInfo[i].Attribute); - const EGLint bVal = GET_CONFIG_ATTRIB(bConfig, SortInfo[i].Attribute); - if (SortInfo[i].SortOrder == SMALLER) { - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; - /* else, continue examining attribute values */ - } - else if (SortInfo[i].SortOrder == SPECIAL) { - if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) { - /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */ - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; + if (conf1 == conf2) + return 0; + + /* the enum values have the desired ordering */ + assert(EGL_NONE < EGL_SLOW_CONFIG); + assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); + val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT); + val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT); + if (val1 != val2) + return (val1 - val2); + + /* the enum values have the desired ordering */ + assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); + val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE); + val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE); + if (val1 != val2) + return (val1 - val2); + rgb_buffer = (val1 == EGL_RGB_BUFFER); + + if (criteria) { + val1 = val2 = 0; + if (rgb_buffer) { + if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) { + val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE); + val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE); } - else if (SortInfo[i].Attribute == EGL_RED_SIZE || - SortInfo[i].Attribute == EGL_GREEN_SIZE || - SortInfo[i].Attribute == EGL_BLUE_SIZE || - SortInfo[i].Attribute == EGL_ALPHA_SIZE) { - if (aVal > bVal) - return -1; - else if (aVal < bVal) - return 1; + if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) { + val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE); + val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE); } - else { - assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE); - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; + if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) { + val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE); + val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE); } } else { - assert(SortInfo[i].SortOrder == NONE); - /* continue examining attribute values */ + if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) { + val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE); + val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE); + } + } + if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) { + val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE); + val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE); } } + else { + /* assume the default criteria, which gives no specific ordering */ + val1 = val2 = 0; + } + + /* for color bits, larger one is preferred */ + if (val1 != val2) + return (val2 - val1); + + for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { + val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]); + val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]); + if (val1 != val2) + return (val1 - val2); + } + + /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ + + if (compare_id) { + val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID); + val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID); + assert(val1 != val2); + } + else { + val1 = val2 = 0; + } + + return (val1 - val2); +} + + +static INLINE +void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) +{ + const _EGLConfig *tmp = *conf1; + *conf1 = *conf2; + *conf2 = tmp; +} + + +/** + * Quick sort an array of configs. This differs from the standard + * qsort() in that the compare function accepts an additional + * argument. + */ +void +_eglSortConfigs(const _EGLConfig **configs, EGLint count, + EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, + void *), + void *priv_data) +{ + const EGLint pivot = 0; + EGLint i, j; + + if (count <= 1) + return; + + _eglSwapConfigs(&configs[pivot], &configs[count / 2]); + i = 1; + j = count - 1; + do { + while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) + i++; + while (compare(configs[j], configs[pivot], priv_data) > 0) + j--; + if (i < j) { + _eglSwapConfigs(&configs[i], &configs[j]); + i++; + j--; + } + else if (i == j) { + i++; + j--; + break; + } + } while (i <= j); + _eglSwapConfigs(&configs[pivot], &configs[j]); - /* all attributes identical */ - return 0; + _eglSortConfigs(configs, j, compare, priv_data); + _eglSortConfigs(configs + i, count - i, compare, priv_data); +} + + +static int +_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, + void *priv_data) +{ + const _EGLConfig *criteria = (const _EGLConfig *) priv_data; + return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); } @@ -324,33 +727,33 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, _EGLConfig **configList, criteria; EGLint i, count; - /* parse the attrib_list to initialize criteria */ - if (!_eglParseConfigAttribs(&criteria, attrib_list)) { - return EGL_FALSE; - } + if (!num_configs) + return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); + + _eglInitConfig(&criteria, 0); + if (!_eglParseConfigAttribList(&criteria, attrib_list)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); /* allocate array of config pointers */ - configList = (_EGLConfig **) malloc(config_size * sizeof(_EGLConfig *)); - if (!configList) { - _eglError(EGL_BAD_CONFIG, "eglChooseConfig(out of memory)"); - return EGL_FALSE; - } + configList = (_EGLConfig **) + malloc(disp->NumConfigs * sizeof(_EGLConfig *)); + if (!configList) + return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); - /* make array of pointers to qualifying configs */ - for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) { - if (_eglConfigQualifies(disp->Configs[i], &criteria)) { + /* perform selection of configs */ + count = 0; + for (i = 0; i < disp->NumConfigs; i++) { + if (_eglMatchConfig(disp->Configs[i], &criteria)) configList[count++] = disp->Configs[i]; - } } - /* sort array of pointers */ - qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs); - - /* copy config handles to output array */ - if (configs) { - for (i = 0; i < count; i++) { - configs[i] = configList[i]->Handle; - } + /* perform sorting of configs */ + if (configs && count) { + _eglSortConfigs((const _EGLConfig **) configList, count, + _eglFallbackCompare, (void *) &criteria); + count = MIN2(count, config_size); + for (i = 0; i < count; i++) + configs[i] = _eglGetConfigHandle(configList[i]); } free(configList); @@ -361,6 +764,28 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, } +static INLINE EGLBoolean +_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) +{ + if (_eglIndexConfig(conf, attr) < 0) + return EGL_FALSE; + + /* there are some holes in the range */ + switch (attr) { + case EGL_PRESERVED_RESOURCES: + case EGL_NONE: +#ifdef EGL_VERSION_1_4 + case EGL_MATCH_NATIVE_PIXMAP: +#endif + return EGL_FALSE; + default: + break; + } + + return EGL_TRUE; +} + + /** * Fallback for eglGetConfigAttrib. */ @@ -368,15 +793,13 @@ EGLBoolean _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLint attribute, EGLint *value) { - const EGLint k = attribute - FIRST_ATTRIB; - if (k >= 0 && k < MAX_ATTRIBS) { - *value = conf->Attrib[k]; - return EGL_TRUE; - } - else { - _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); - return EGL_FALSE; - } + if (!_eglIsConfigAttribValid(conf, attribute)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); + + *value = GET_CONFIG_ATTRIB(conf, attribute); + return EGL_TRUE; } @@ -387,12 +810,14 @@ EGLBoolean _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, EGLint config_size, EGLint *num_config) { + if (!num_config) + return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); + if (configs) { EGLint i; *num_config = MIN2(disp->NumConfigs, config_size); - for (i = 0; i < *num_config; i++) { - configs[i] = disp->Configs[i]->Handle; - } + for (i = 0; i < *num_config; i++) + configs[i] = _eglGetConfigHandle(disp->Configs[i]); } else { /* just return total number of supported configs */ diff --git a/src/egl/main/eglconfig.h b/src/egl/main/eglconfig.h index 36ed96ae95..6b8a259984 100644 --- a/src/egl/main/eglconfig.h +++ b/src/egl/main/eglconfig.h @@ -2,27 +2,93 @@ #define EGLCONFIG_INCLUDED +#include <assert.h> #include "egltypedefs.h" -#include <GLES/gl.h> -#define MAX_ATTRIBS 128 -#define FIRST_ATTRIB EGL_BUFFER_SIZE +#define _EGL_CONFIG_FIRST_ATTRIB EGL_BUFFER_SIZE +#define _EGL_CONFIG_LAST_ATTRIB EGL_CONFORMANT +#define _EGL_CONFIG_NUM_ATTRIBS \ + (_EGL_CONFIG_LAST_ATTRIB - _EGL_CONFIG_FIRST_ATTRIB + 1) + +#define _EGL_CONFIG_STORAGE_SIZE _EGL_CONFIG_NUM_ATTRIBS struct _egl_config { - EGLConfig Handle; /* the public/opaque handle which names this config */ - EGLint Attrib[MAX_ATTRIBS]; + _EGLDisplay *Display; + EGLint Storage[_EGL_CONFIG_STORAGE_SIZE]; }; -#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) \ - assert((ATTR) - FIRST_ATTRIB < MAX_ATTRIBS); \ - ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB] = VAL) +#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) _eglSetConfigKey(CONF, ATTR, VAL) +#define GET_CONFIG_ATTRIB(CONF, ATTR) _eglGetConfigKey(CONF, ATTR) + + +/** + * Given a key, return an index into the storage of the config. + * Return -1 if the key is invalid. + */ +static INLINE EGLint +_eglIndexConfig(const _EGLConfig *conf, EGLint key) +{ + (void) conf; + if (key >= _EGL_CONFIG_FIRST_ATTRIB && + key < _EGL_CONFIG_FIRST_ATTRIB + _EGL_CONFIG_NUM_ATTRIBS) + return key - _EGL_CONFIG_FIRST_ATTRIB; + else + return -1; +} + + +/** + * Reset all keys in the config to a given value. + */ +static INLINE void +_eglResetConfigKeys(_EGLConfig *conf, EGLint val) +{ + EGLint i; + for (i = 0; i < _EGL_CONFIG_NUM_ATTRIBS; i++) + conf->Storage[i] = val; +} -#define GET_CONFIG_ATTRIB(CONF, ATTR) ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB]) +/** + * Update a config for a given key. + */ +static INLINE void +_eglSetConfigKey(_EGLConfig *conf, EGLint key, EGLint val) +{ + EGLint idx = _eglIndexConfig(conf, key); + assert(idx >= 0); + conf->Storage[idx] = val; +} + + +/** + * Return the value for a given key. + */ +static INLINE EGLint +_eglGetConfigKey(const _EGLConfig *conf, EGLint key) +{ + EGLint idx = _eglIndexConfig(conf, key); + assert(idx >= 0); + return conf->Storage[idx]; +} + + +/** + * Set a given attribute. + * + * Because _eglGetConfigAttrib is already used as a fallback driver + * function, this function is not considered to have a good name. + * SET_CONFIG_ATTRIB is preferred over this function. + */ +static INLINE void +_eglSetConfigAttrib(_EGLConfig *conf, EGLint attr, EGLint val) +{ + SET_CONFIG_ATTRIB(conf, attr, val); +} extern void @@ -30,19 +96,76 @@ _eglInitConfig(_EGLConfig *config, EGLint id); extern EGLConfig -_eglGetConfigHandle(_EGLConfig *config); +_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf); + + +#ifndef _EGL_SKIP_HANDLE_CHECK + + +extern EGLBoolean +_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy); + + +#else + +static INLINE EGLBoolean +_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy) +{ + _EGLConfig *conf = (_EGLConfig *) config; + return (dpy && conf && conf->Display == dpy); +} + + +#endif /* _EGL_SKIP_HANDLE_CHECK */ -extern _EGLConfig * -_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy); + +/** + * Lookup a handle to find the linked config. + * Return NULL if the handle has no corresponding linked config. + */ +static INLINE _EGLConfig * +_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy) +{ + _EGLConfig *conf = (_EGLConfig *) config; + if (!_eglCheckConfigHandle(config, dpy)) + conf = NULL; + return conf; +} + + +/** + * Return the handle of a linked config, or NULL. + */ +static INLINE EGLConfig +_eglGetConfigHandle(_EGLConfig *conf) +{ + return (EGLConfig) ((conf && conf->Display) ? conf : NULL); +} + + +extern EGLBoolean +_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching); -extern _EGLConfig * -_eglAddConfig(_EGLDisplay *display, _EGLConfig *config); +extern EGLBoolean +_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria); extern EGLBoolean -_eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list); +_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list); + + +extern EGLint +_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, + const _EGLConfig *criteria, EGLBoolean compare_id); + + +extern void +_eglSortConfigs(const _EGLConfig **configs, EGLint count, + EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, + void *), + void *priv_data); extern EGLBoolean @@ -57,8 +180,4 @@ extern EGLBoolean _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); -extern void -_eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val); - - #endif /* EGLCONFIG_INCLUDED */ diff --git a/src/egl/main/eglconfigutil.c b/src/egl/main/eglconfigutil.c index c9d00e7982..36e94f0d2d 100644 --- a/src/egl/main/eglconfigutil.c +++ b/src/egl/main/eglconfigutil.c @@ -52,6 +52,83 @@ _eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode) } +/** + * Convert a __GLcontextModes object to an _EGLConfig. + */ +EGLBoolean +_eglConfigFromContextModesRec(_EGLConfig *conf, const __GLcontextModes *m, + EGLint conformant, EGLint renderable_type) +{ + EGLint config_caveat, surface_type; + + /* must be RGBA */ + if (!m->rgbMode || !(m->renderType & GLX_RGBA_BIT)) + return EGL_FALSE; + + config_caveat = EGL_NONE; + if (m->visualRating == GLX_SLOW_CONFIG) + config_caveat = EGL_SLOW_CONFIG; + + if (m->visualRating == GLX_NON_CONFORMANT_CONFIG) + conformant &= ~EGL_OPENGL_BIT; + if (!(conformant & EGL_OPENGL_ES_BIT)) + config_caveat = EGL_NON_CONFORMANT_CONFIG; + + surface_type = 0; + if (m->drawableType & GLX_WINDOW_BIT) + surface_type |= EGL_WINDOW_BIT; + if (m->drawableType & GLX_PIXMAP_BIT) + surface_type |= EGL_PIXMAP_BIT; + if (m->drawableType & GLX_PBUFFER_BIT) + surface_type |= EGL_PBUFFER_BIT; + + SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, m->rgbBits); + SET_CONFIG_ATTRIB(conf, EGL_RED_SIZE, m->redBits); + SET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE, m->greenBits); + SET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE, m->blueBits); + SET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE, m->alphaBits); + + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, m->bindToTextureRgb); + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, m->bindToTextureRgba); + SET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); + SET_CONFIG_ATTRIB(conf, EGL_CONFIG_CAVEAT, config_caveat); + + SET_CONFIG_ATTRIB(conf, EGL_CONFORMANT, conformant); + SET_CONFIG_ATTRIB(conf, EGL_DEPTH_SIZE, m->depthBits); + SET_CONFIG_ATTRIB(conf, EGL_LEVEL, m->level); + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_WIDTH, m->maxPbufferWidth); + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_HEIGHT, m->maxPbufferHeight); + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_PIXELS, m->maxPbufferPixels); + + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, m->xRenderable); + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, m->visualID); + + if (m->visualType != GLX_NONE) + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, m->visualType); + else + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE); + + SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, renderable_type); + SET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS, m->sampleBuffers); + SET_CONFIG_ATTRIB(conf, EGL_SAMPLES, m->samples); + SET_CONFIG_ATTRIB(conf, EGL_STENCIL_SIZE, m->stencilBits); + + SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type); + + /* what to do with GLX_TRANSPARENT_INDEX? */ + if (m->transparentPixel == GLX_TRANSPARENT_RGB) { + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, m->transparentRed); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, m->transparentGreen); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, m->transparentBlue); + } + else { + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE, EGL_NONE); + } + + return EGL_TRUE; +} + /** * Creates a set of \c _EGLConfigs that a driver will expose. diff --git a/src/egl/main/eglconfigutil.h b/src/egl/main/eglconfigutil.h index c477b94737..8c923ee206 100644 --- a/src/egl/main/eglconfigutil.h +++ b/src/egl/main/eglconfigutil.h @@ -1,12 +1,10 @@ - #ifndef EGLCONFIGUTIL_INCLUDED #define EGLCONFIGUTIL_INCLUDED -#include "eglconfig.h" + +#include "GL/gl.h" #include "GL/internal/glcore.h" -#if (!defined(WIN32) && !defined(_WIN32_WCE)) -#include "stdint.h" -#endif +#include "eglconfig.h" extern void @@ -14,6 +12,11 @@ _eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode); extern EGLBoolean +_eglConfigFromContextModesRec(_EGLConfig *conf, const __GLcontextModes *m, + EGLint conformant, EGLint renderable_type); + + +extern EGLBoolean _eglFillInConfigs( _EGLConfig *configs, EGLenum fb_format, EGLenum fb_type, const uint8_t * depth_bits, const uint8_t * stencil_bits, diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index b094f49bfc..ee4b1b59f5 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -45,6 +45,7 @@ _eglInitContext(_EGLDriver *drv, _EGLContext *ctx, ctx->DrawSurface = EGL_NO_SURFACE; ctx->ReadSurface = EGL_NO_SURFACE; ctx->ClientAPI = api; + ctx->WindowRenderBuffer = EGL_NONE; return EGL_TRUE; } @@ -87,6 +88,24 @@ _eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) } +#ifdef EGL_VERSION_1_2 +static EGLint +_eglQueryContextRenderBuffer(_EGLContext *ctx) +{ + _EGLSurface *surf = ctx->DrawSurface; + EGLint rb; + + if (!surf) + return EGL_NONE; + if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE) + rb = ctx->WindowRenderBuffer; + else + rb = surf->RenderBuffer; + return rb; +} +#endif /* EGL_VERSION_1_2 */ + + EGLBoolean _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, EGLint attribute, EGLint *value) @@ -94,22 +113,29 @@ _eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, (void) drv; (void) dpy; + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglQueryContext"); + switch (attribute) { case EGL_CONFIG_ID: *value = GET_CONFIG_ATTRIB(c->Config, EGL_CONFIG_ID); - return EGL_TRUE; + break; + case EGL_CONTEXT_CLIENT_VERSION: + *value = c->ClientVersion; + break; #ifdef EGL_VERSION_1_2 case EGL_CONTEXT_CLIENT_TYPE: *value = c->ClientAPI; - return EGL_TRUE; + break; + case EGL_RENDER_BUFFER: + *value = _eglQueryContextRenderBuffer(c); + break; #endif /* EGL_VERSION_1_2 */ - case EGL_CONTEXT_CLIENT_VERSION: - *value = c->ClientVersion; - return EGL_TRUE; default: - _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); - return EGL_FALSE; + return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); } + + return EGL_TRUE; } diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h index 647f24488f..45c7b4717b 100644 --- a/src/egl/main/eglcontext.h +++ b/src/egl/main/eglcontext.h @@ -24,6 +24,9 @@ struct _egl_context EGLint ClientAPI; /**< EGL_OPENGL_ES_API, EGL_OPENGL_API, EGL_OPENVG_API */ EGLint ClientVersion; /**< 1 = OpenGLES 1.x, 2 = OpenGLES 2.x */ + + /* The real render buffer when a window surface is bound */ + EGLint WindowRenderBuffer; }; diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c index 4431f964f6..df506151b5 100644 --- a/src/egl/main/eglcurrent.c +++ b/src/egl/main/eglcurrent.c @@ -9,14 +9,14 @@ /* This should be kept in sync with _eglInitThreadInfo() */ #define _EGL_THREAD_INFO_INITIALIZER \ - { EGL_SUCCESS, { NULL }, 1 } + { EGL_SUCCESS, { NULL }, 0 } /* a fallback thread info to guarantee that every thread always has one */ static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER; #ifdef GLX_USE_TLS -static __thread const _EGLThreadInfo *_egl_TSD; +static __thread const _EGLThreadInfo *_egl_TSD __attribute__ ((tls_model("initial-exec"))); static INLINE void _eglSetTSD(const _EGLThreadInfo *t) diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h index 8eb241029e..9503e0aba0 100644 --- a/src/egl/main/eglcurrent.h +++ b/src/egl/main/eglcurrent.h @@ -4,8 +4,16 @@ #include "egltypedefs.h" -#define _EGL_API_NUM_INDICES \ - (EGL_OPENGL_API - EGL_OPENGL_ES_API + 2) /* idx 0 is for EGL_NONE */ +#define _EGL_API_ALL_BITS \ + (EGL_OPENGL_ES_BIT | \ + EGL_OPENVG_BIT | \ + EGL_OPENGL_ES2_BIT | \ + EGL_OPENGL_BIT) + + +#define _EGL_API_FIRST_API EGL_OPENGL_ES_API +#define _EGL_API_LAST_API EGL_OPENGL_API +#define _EGL_API_NUM_APIS (_EGL_API_LAST_API - _EGL_API_FIRST_API + 1) /** @@ -14,20 +22,19 @@ struct _egl_thread_info { EGLint LastError; - _EGLContext *CurrentContexts[_EGL_API_NUM_INDICES]; + _EGLContext *CurrentContexts[_EGL_API_NUM_APIS]; /* use index for fast access to current context */ EGLint CurrentAPIIndex; }; /** - * Return true if a client API enum can be converted to an index. + * Return true if a client API enum is recognized. */ static INLINE EGLBoolean _eglIsApiValid(EGLenum api) { - return ((api >= EGL_OPENGL_ES_API && api <= EGL_OPENGL_API) || - api == EGL_NONE); + return (api >= _EGL_API_FIRST_API && api <= _EGL_API_LAST_API); } @@ -38,7 +45,7 @@ _eglIsApiValid(EGLenum api) static INLINE EGLint _eglConvertApiToIndex(EGLenum api) { - return (api != EGL_NONE) ? api - EGL_OPENGL_ES_API + 1 : 0; + return api - _EGL_API_FIRST_API; } @@ -49,7 +56,7 @@ _eglConvertApiToIndex(EGLenum api) static INLINE EGLenum _eglConvertApiFromIndex(EGLint idx) { - return (idx) ? EGL_OPENGL_ES_API + idx - 1 : EGL_NONE; + return _EGL_API_FIRST_API + idx; } diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 6575fdf198..ea4e35a8b3 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -44,6 +44,7 @@ struct _egl_display EGLint NumScreens; _EGLScreen **Screens; /* array [NumScreens] */ + EGLint MaxConfigs; EGLint NumConfigs; _EGLConfig **Configs; /* array [NumConfigs] of ptr to _EGLConfig */ diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index 87786e36bb..018b06d3be 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -22,59 +22,70 @@ #if defined(_EGL_PLATFORM_X) #include <dlfcn.h> -#elif defined(_EGL_PLATFORM_WINDOWS) -/* Use static linking on Windows for now */ -#define WINDOWS_STATIC_LINK #endif + /** * Wrappers for dlopen/dlclose() */ #if defined(_EGL_PLATFORM_WINDOWS) -#ifdef WINDOWS_STATIC_LINK - static const char *DefaultDriverName = "Windows EGL Static Library"; -#else - /* XXX Need to decide how to do dynamic name lookup on Windows */ - static const char *DefaultDriverName = "TBD"; -#endif - typedef HMODULE lib_handle; - - static HMODULE - open_library(const char *filename) - { -#ifdef WINDOWS_STATIC_LINK - return 0; -#else - return LoadLibrary(filename); -#endif - } - static void - close_library(HMODULE lib) - { -#ifdef WINDOWS_STATIC_LINK -#else - FreeLibrary(lib); -#endif - } + +/* XXX Need to decide how to do dynamic name lookup on Windows */ +static const char DefaultDriverName[] = "TBD"; + +typedef HMODULE lib_handle; + +static HMODULE +open_library(const char *filename) +{ + return LoadLibrary(filename); +} + +static void +close_library(HMODULE lib) +{ + FreeLibrary(lib); +} + #elif defined(_EGL_PLATFORM_X) - static const char *DefaultDriverName = "egl_softpipe"; - typedef void * lib_handle; - static void * - open_library(const char *filename) - { - return dlopen(filename, RTLD_LAZY); - } +static const char DefaultDriverName[] = "egl_softpipe"; + +typedef void * lib_handle; + +static void * +open_library(const char *filename) +{ + return dlopen(filename, RTLD_LAZY); +} + +static void +close_library(void *lib) +{ + dlclose(lib); +} + +#else /* _EGL_PLATFORM_NO_OS */ + +static const char DefaultDriverName[] = "builtin"; + +typedef void *lib_handle; + +static INLINE void * +open_library(const char *filename) +{ + return (void *) filename; +} + +static INLINE void +close_library(void *lib) +{ +} + - static void - close_library(void *lib) - { - dlclose(lib); - } - #endif @@ -95,14 +106,22 @@ _eglChooseDriver(_EGLDisplay *dpy, char **argsRet) path = _eglstrdup(path); #if defined(_EGL_PLATFORM_X) - if (!path && dpy->NativeDisplay) { + if (!path && dpy && dpy->NativeDisplay) { /* assume (wrongly!) that the native display is a display string */ path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args); } suffix = "so"; #elif defined(_EGL_PLATFORM_WINDOWS) suffix = "dll"; -#endif /* _EGL_PLATFORM_X */ +#else /* _EGL_PLATFORM_NO_OS */ + if (path) { + /* force the use of the default driver */ + _eglLog(_EGL_DEBUG, "ignore EGL_DRIVER"); + free(path); + path = NULL; + } + suffix = NULL; +#endif if (!path) path = _eglstrdup(DefaultDriverName); @@ -136,43 +155,48 @@ _eglChooseDriver(_EGLDisplay *dpy, char **argsRet) static _EGLMain_t _eglOpenLibrary(const char *driverPath, lib_handle *handle) { - _EGLMain_t mainFunc; lib_handle lib; + _EGLMain_t mainFunc = NULL; + const char *error = "unknown error"; assert(driverPath); -#if defined(_EGL_PLATFORM_WINDOWS) -/* Use static linking on Windows for now */ -#ifdef WINDOWS_STATIC_LINK - lib = 0; - mainFunc = (_EGLMain_t)_eglMain; -#else - /* XXX untested */ _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath); lib = open_library(driverPath); - if (!lib) { - _eglLog(_EGL_WARNING, "Could not open %s", - driverPath); - return NULL; + +#if defined(_EGL_PLATFORM_WINDOWS) + /* XXX untested */ + if (lib) + mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); +#elif defined(_EGL_PLATFORM_X) + if (lib) { + mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain"); + if (!mainFunc) + error = dlerror(); + } + else { + error = dlerror(); } - mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); +#else /* _EGL_PLATFORM_NO_OS */ + /* must be the default driver name */ + if (strcmp(driverPath, DefaultDriverName) == 0) + mainFunc = (_EGLMain_t) _eglMain; + else + error = "not builtin driver"; #endif -#elif defined(_EGL_PLATFORM_X) - _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath); - lib = open_library(driverPath); + if (!lib) { - _eglLog(_EGL_WARNING, "Could not open %s (%s)", - driverPath, dlerror()); + _eglLog(_EGL_WARNING, "Could not open driver %s (%s)", + driverPath, error); if (!getenv("EGL_DRIVER")) _eglLog(_EGL_WARNING, "The driver can be overridden by setting EGL_DRIVER"); return NULL; } - mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain"); -#endif if (!mainFunc) { - _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverPath); + _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)", + driverPath, error); if (lib) close_library(lib); return NULL; @@ -384,7 +408,7 @@ _eglInitDriverFallbacks(_EGLDriver *drv) drv->API.CopyBuffers = _eglCopyBuffers; drv->API.QueryString = _eglQueryString; - drv->API.WaitGL = _eglWaitGL; + drv->API.WaitClient = _eglWaitClient; drv->API.WaitNative = _eglWaitNative; #ifdef EGL_MESA_screen_surface @@ -428,6 +452,11 @@ _eglFindAPIs(void) const char *es2_libname = "libGLESv2.so"; const char *gl_libname = "libGL.so"; const char *vg_libname = "libOpenVG.so"; +#else /* _EGL_PLATFORM_NO_OS */ + const char *es1_libname = NULL; + const char *es2_libname = NULL; + const char *gl_libname = NULL; + const char *vg_libname = NULL; #endif if ((lib = open_library(es1_libname))) { diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c index 3ae4c1ad3a..443d0f072c 100644 --- a/src/egl/main/eglglobals.c +++ b/src/egl/main/eglglobals.c @@ -15,13 +15,13 @@ struct _egl_global _eglGlobal = &_eglGlobalMutex, /* Mutex */ NULL, /* DisplayList */ 1, /* FreeScreenHandle */ - 0x0, /* ClientAPIsMask */ 0, /* NumDrivers */ { NULL }, /* Drivers */ 2, /* NumAtExitCalls */ - { /* AtExitCalls */ - _eglFiniDisplay, - _eglUnloadDrivers + { + /* default AtExitCalls, called in reverse order */ + _eglUnloadDrivers, /* always called last */ + _eglFiniDisplay }, }; diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h index 58511076d4..5ebb914ca7 100644 --- a/src/egl/main/eglglobals.h +++ b/src/egl/main/eglglobals.h @@ -19,9 +19,6 @@ struct _egl_global EGLScreenMESA FreeScreenHandle; - /* bitmaks of supported APIs (supported by _some_ driver) */ - EGLint ClientAPIsMask; - EGLint NumDrivers; _EGLDriver *Drivers[10]; diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c index 1d7a0a388c..11a9bf7275 100644 --- a/src/egl/main/egllog.c +++ b/src/egl/main/egllog.c @@ -9,51 +9,140 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> + #include "egllog.h" +#include "eglmutex.h" #define MAXSTRING 1000 -#define FALLBACK_LOG_LEVEL _EGL_WARNING -#define FALLBACK_LOG_LEVEL_STR "warning" +#define FALLBACK_LOG_LEVEL _EGL_WARNING -static EGLint ReportingLevel = -1; +static struct { + _EGLMutex mutex; -static void -log_level_initialize(void) + EGLBoolean initialized; + EGLint level; + _EGLLogProc logger; + EGLint num_messages; +} logging = { + _EGL_MUTEX_INITIALIZER, + EGL_FALSE, + FALLBACK_LOG_LEVEL, + NULL, + 0 +}; + +static const char *level_strings[] = { + /* the order is important */ + "fatal", + "warning", + "info", + "debug", + NULL +}; + + +/** + * Set the function to be called when there is a message to log. + * Note that the function will be called with an internal lock held. + * Recursive logging is not allowed. + */ +void +_eglSetLogProc(_EGLLogProc logger) { -#if defined(_EGL_PLATFORM_X) - char *log_env = getenv("EGL_LOG_LEVEL"); -#else - char *log_env = NULL; -#endif - - if (log_env == NULL) { - ReportingLevel = FALLBACK_LOG_LEVEL; - } - else if (strcasecmp(log_env, "fatal") == 0) { - ReportingLevel = _EGL_FATAL; - } - else if (strcasecmp(log_env, "warning") == 0) { - ReportingLevel = _EGL_WARNING; + EGLint num_messages = 0; + + _eglLockMutex(&logging.mutex); + + if (logging.logger != logger) { + logging.logger = logger; + + num_messages = logging.num_messages; + logging.num_messages = 0; } - else if (strcasecmp(log_env, "info") == 0) { - ReportingLevel = _EGL_INFO; + + _eglUnlockMutex(&logging.mutex); + + if (num_messages) + _eglLog(_EGL_DEBUG, + "New logger installed. " + "Messages before the new logger might not be available."); +} + + +/** + * Set the log reporting level. + */ +void +_eglSetLogLevel(EGLint level) +{ + switch (level) { + case _EGL_FATAL: + case _EGL_WARNING: + case _EGL_INFO: + case _EGL_DEBUG: + _eglLockMutex(&logging.mutex); + logging.level = level; + _eglUnlockMutex(&logging.mutex); + break; + default: + break; } - else if (strcasecmp(log_env, "debug") == 0) { - ReportingLevel = _EGL_DEBUG; +} + + +/** + * The default logger. It prints the message to stderr. + */ +static void +_eglDefaultLogger(EGLint level, const char *msg) +{ + fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg); +} + + +/** + * Initialize the logging facility. + */ +static void +_eglInitLogger(void) +{ + const char *log_env; + EGLint i, level = -1; + + if (logging.initialized) + return; + + log_env = getenv("EGL_LOG_LEVEL"); + if (log_env) { + for (i = 0; level_strings[i]; i++) { + if (strcasecmp(log_env, level_strings[i]) == 0) { + level = i; + break; + } + } } else { - fprintf(stderr, "Unrecognized EGL_LOG_LEVEL environment variable value. " + level = FALLBACK_LOG_LEVEL; + } + + logging.logger = _eglDefaultLogger; + logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL; + logging.initialized = EGL_TRUE; + + /* it is fine to call _eglLog now */ + if (log_env && level < 0) { + _eglLog(_EGL_WARNING, + "Unrecognized EGL_LOG_LEVEL environment variable value. " "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". " - "Got \"%s\". Falling back to \"%s\".\n", - log_env, FALLBACK_LOG_LEVEL_STR); - ReportingLevel = FALLBACK_LOG_LEVEL; + "Got \"%s\". Falling back to \"%s\".", + log_env, level_strings[FALLBACK_LOG_LEVEL]); } } /** - * Log a message to stderr. + * Log a message with message logger. * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG. */ void @@ -61,40 +150,26 @@ _eglLog(EGLint level, const char *fmtStr, ...) { va_list args; char msg[MAXSTRING]; - const char *levelStr; - static int log_level_initialized = 0; - if (!log_level_initialized) { - log_level_initialize(); - log_level_initialized = 1; - } + /* one-time initialization; a little race here is fine */ + if (!logging.initialized) + _eglInitLogger(); + if (level > logging.level || level < 0) + return; - if (level <= ReportingLevel) { - switch (level) { - case _EGL_FATAL: - levelStr = "Fatal"; - break; - case _EGL_WARNING: - levelStr = "Warning"; - break; - case _EGL_INFO: - levelStr = "Info"; - break; - case _EGL_DEBUG: - levelStr = "Debug"; - break; - default: - levelStr = ""; - } + _eglLockMutex(&logging.mutex); + if (logging.logger) { va_start(args, fmtStr); vsnprintf(msg, MAXSTRING, fmtStr, args); va_end(args); - fprintf(stderr, "libEGL %s: %s\n", levelStr, msg); - - if (level == _EGL_FATAL) { - exit(1); /* or abort()? */ - } + logging.logger(level, msg); + logging.num_messages++; } + + _eglUnlockMutex(&logging.mutex); + + if (level == _EGL_FATAL) + exit(1); /* or abort()? */ } diff --git a/src/egl/main/egllog.h b/src/egl/main/egllog.h index 2fa352f155..83c8bb72a6 100644 --- a/src/egl/main/egllog.h +++ b/src/egl/main/egllog.h @@ -9,6 +9,17 @@ #define _EGL_DEBUG 3 /* useful info for debugging */ +typedef void (*_EGLLogProc)(EGLint level, const char *msg); + + +extern void +_eglSetLogProc(_EGLLogProc logger); + + +extern void +_eglSetLogLevel(EGLint level); + + extern void _eglLog(EGLint level, const char *fmtStr, ...); diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c index b37213faf1..e66913320b 100644 --- a/src/egl/main/eglmisc.c +++ b/src/egl/main/eglmisc.c @@ -108,11 +108,12 @@ _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name) EGLBoolean -_eglWaitGL(_EGLDriver *drv, _EGLDisplay *dpy) +_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) { /* just a placeholder */ (void) drv; (void) dpy; + (void) ctx; return EGL_TRUE; } diff --git a/src/egl/main/eglmisc.h b/src/egl/main/eglmisc.h index a15c839be2..829d4cde79 100644 --- a/src/egl/main/eglmisc.h +++ b/src/egl/main/eglmisc.h @@ -37,7 +37,7 @@ _eglQueryString(_EGLDriver *drv, _EGLDisplay *dpy, EGLint name); extern EGLBoolean -_eglWaitGL(_EGLDriver *drv, _EGLDisplay *dpy); +_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx); extern EGLBoolean diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c index e7a1a8329e..940a1b760c 100644 --- a/src/egl/main/eglsurface.c +++ b/src/egl/main/eglsurface.c @@ -15,6 +15,22 @@ #include "eglsurface.h" +static void +_eglClampSwapInterval(_EGLSurface *surf, EGLint interval) +{ + EGLint bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MAX_SWAP_INTERVAL); + if (interval >= bound) { + interval = bound; + } + else { + bound = GET_CONFIG_ATTRIB(surf->Config, EGL_MIN_SWAP_INTERVAL); + if (interval < bound) + interval = bound; + } + surf->SwapInterval = interval; +} + + /** * Do error check on parameters and initialize the given _EGLSurface object. * \return EGL_TRUE if no errors, EGL_FALSE otherwise. @@ -194,7 +210,9 @@ _eglInitSurface(_EGLDriver *drv, _EGLSurface *surf, EGLint type, surf->TextureTarget = texTarget; surf->MipmapTexture = mipmapTex; surf->MipmapLevel = 0; - surf->SwapInterval = 0; + /* the default swap interval is 1 */ + _eglClampSwapInterval(surf, 1); + #ifdef EGL_VERSION_1_2 surf->SwapBehavior = EGL_BUFFER_DESTROYED; /* XXX ok? */ surf->HorizontalResolution = EGL_UNKNOWN; /* set by caller */ @@ -466,11 +484,10 @@ _eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, EGLBoolean -_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, EGLint interval) +_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, + EGLint interval) { - _EGLSurface *surf = _eglGetCurrentSurface(EGL_DRAW); - if (surf) - surf->SwapInterval = interval; + _eglClampSwapInterval(surf, interval); return EGL_TRUE; } diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h index f6d44b5922..b75fa9c368 100644 --- a/src/egl/main/eglsurface.h +++ b/src/egl/main/eglsurface.h @@ -86,7 +86,7 @@ _eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint extern EGLBoolean -_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, EGLint interval); +_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval); #ifdef EGL_VERSION_1_2 |