X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fglx%2Fegl_glx.c;h=5ed4b6883f885983bf7d03d0c51ea444d25b5dd3;hb=c98ea26e16b6458b4385d6558936696e4d099455;hp=9a421b5a80b3d661bcb0b98ffcc36caef11924e8;hpb=5aaeb13a768f0c7d3706f6c170901b118ae1aa2d;p=mesa.git diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c index 9a421b5a80b..5fce06d66df 100644 --- a/src/egl/drivers/glx/egl_glx.c +++ b/src/egl/drivers/glx/egl_glx.c @@ -33,85 +33,108 @@ * Authors: Alan Hourihane */ -/* - * TODO: - * - * Add GLXFBConfig support - * Pbuffer & Pixmap support - * test eglBind/ReleaseTexImage - */ - - -#include -#include -#include -#include -#include -#include "dlfcn.h" +#include +#include #include -#include -#include "glxclient.h" - -#define _EGL_PLATFORM_X +#include +#include "GL/glx.h" #include "eglconfig.h" #include "eglcontext.h" +#include "egldefines.h" #include "egldisplay.h" #include "egldriver.h" -#include "eglglobals.h" -#include "eglhash.h" +#include "eglcurrent.h" #include "egllog.h" #include "eglsurface.h" -#include - #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T)) -static const EGLint all_apis = (EGL_OPENGL_ES_BIT - | EGL_OPENGL_ES2_BIT - | EGL_OPENVG_BIT - /* | EGL_OPENGL_BIT */); /* can't do */ +#ifndef GLX_VERSION_1_4 +#error "GL/glx.h must be equal to or greater than GLX 1.4" +#endif -struct visual_attribs -{ - /* X visual attribs */ - int id; - int klass; - int depth; - int redMask, greenMask, blueMask; - int colormapSize; - int bitsPerRGB; - - /* 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; -}; +/* GLX 1.0 */ +typedef GLXContext (*GLXCREATECONTEXTPROC)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct ); +typedef void (*GLXDESTROYCONTEXTPROC)( Display *dpy, GLXContext ctx ); +typedef Bool (*GLXMAKECURRENTPROC)( Display *dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*GLXSWAPBUFFERSPROC)( Display *dpy, GLXDrawable drawable ); +typedef GLXPixmap (*GLXCREATEGLXPIXMAPPROC)( Display *dpy, XVisualInfo *visual, Pixmap pixmap ); +typedef void (*GLXDESTROYGLXPIXMAPPROC)( Display *dpy, GLXPixmap pixmap ); +typedef Bool (*GLXQUERYVERSIONPROC)( Display *dpy, int *maj, int *min ); +typedef int (*GLXGETCONFIGPROC)( Display *dpy, XVisualInfo *visual, int attrib, int *value ); +typedef void (*GLXWAITGLPROC)( void ); +typedef void (*GLXWAITXPROC)( void ); + +/* GLX 1.1 */ +typedef const char *(*GLXQUERYEXTENSIONSSTRINGPROC)( Display *dpy, int screen ); +typedef const char *(*GLXQUERYSERVERSTRINGPROC)( Display *dpy, int screen, int name ); +typedef const char *(*GLXGETCLIENTSTRINGPROC)( Display *dpy, int name ); /** subclass of _EGLDriver */ struct GLX_egl_driver { _EGLDriver Base; /**< base class */ + void *handle; + + /* GLX 1.0 */ + GLXCREATECONTEXTPROC glXCreateContext; + GLXDESTROYCONTEXTPROC glXDestroyContext; + GLXMAKECURRENTPROC glXMakeCurrent; + GLXSWAPBUFFERSPROC glXSwapBuffers; + GLXCREATEGLXPIXMAPPROC glXCreateGLXPixmap; + GLXDESTROYGLXPIXMAPPROC glXDestroyGLXPixmap; + GLXQUERYVERSIONPROC glXQueryVersion; + GLXGETCONFIGPROC glXGetConfig; + GLXWAITGLPROC glXWaitGL; + GLXWAITXPROC glXWaitX; + + /* GLX 1.1 */ + GLXQUERYEXTENSIONSSTRINGPROC glXQueryExtensionsString; + GLXQUERYSERVERSTRINGPROC glXQueryServerString; + GLXGETCLIENTSTRINGPROC glXGetClientString; + + /* GLX 1.3 or (GLX_SGI_make_current_read and GLX_SGIX_fbconfig) */ + PFNGLXGETFBCONFIGSPROC glXGetFBConfigs; + PFNGLXGETFBCONFIGATTRIBPROC glXGetFBConfigAttrib; + PFNGLXGETVISUALFROMFBCONFIGPROC glXGetVisualFromFBConfig; + PFNGLXCREATEWINDOWPROC glXCreateWindow; + PFNGLXDESTROYWINDOWPROC glXDestroyWindow; + PFNGLXCREATEPIXMAPPROC glXCreatePixmap; + PFNGLXDESTROYPIXMAPPROC glXDestroyPixmap; + PFNGLXCREATEPBUFFERPROC glXCreatePbuffer; + PFNGLXDESTROYPBUFFERPROC glXDestroyPbuffer; + PFNGLXCREATENEWCONTEXTPROC glXCreateNewContext; + PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrent; + + /* GLX 1.4 or GLX_ARB_get_proc_address */ + PFNGLXGETPROCADDRESSPROC glXGetProcAddress; + + /* GLX_SGIX_pbuffer */ + PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX; + PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX; +}; + + +/** driver data of _EGLDisplay */ +struct GLX_egl_display +{ + Display *dpy; XVisualInfo *visuals; + GLXFBConfig *fbconfigs; + + int glx_maj, glx_min; - /* GLXFBConfig *fbconfigs - todo */ + const char *extensions; + EGLBoolean have_1_3; + EGLBoolean have_make_current_read; + EGLBoolean have_fbconfig; + EGLBoolean have_pbuffer; + + /* workaround quirks of different GLX implementations */ + EGLBoolean single_buffered_quirk; + EGLBoolean glx_window_quirk; }; @@ -129,7 +152,10 @@ struct GLX_egl_surface { _EGLSurface Base; /**< base class */ - GLXDrawable drawable; + Drawable drawable; + GLXDrawable glx_drawable; + + void (*destroy)(Display *, GLXDrawable); }; @@ -137,189 +163,474 @@ struct GLX_egl_surface struct GLX_egl_config { _EGLConfig Base; /**< base class */ + EGLBoolean double_buffered; + int index; }; -/** cast wrapper */ -static struct GLX_egl_driver * -GLX_egl_driver(_EGLDriver *drv) -{ - return (struct GLX_egl_driver *) drv; -} +/* standard typecasts */ +_EGL_DRIVER_STANDARD_TYPECASTS(GLX_egl) -static struct GLX_egl_context * -GLX_egl_context(_EGLContext *ctx) +static int +GLX_egl_config_index(_EGLConfig *conf) { - return (struct GLX_egl_context *) ctx; + struct GLX_egl_config *GLX_conf = GLX_egl_config(conf); + return GLX_conf->index; } -static struct GLX_egl_surface * -GLX_egl_surface(_EGLSurface *surf) + +static const struct { + int attr; + int egl_attr; +} fbconfig_attributes[] = { + /* table 3.1 of GLX 1.4 */ + { GLX_FBCONFIG_ID, 0 }, + { GLX_BUFFER_SIZE, EGL_BUFFER_SIZE }, + { GLX_LEVEL, EGL_LEVEL }, + { GLX_DOUBLEBUFFER, 0 }, + { GLX_STEREO, 0 }, + { GLX_AUX_BUFFERS, 0 }, + { GLX_RED_SIZE, EGL_RED_SIZE }, + { GLX_GREEN_SIZE, EGL_GREEN_SIZE }, + { GLX_BLUE_SIZE, EGL_BLUE_SIZE }, + { GLX_ALPHA_SIZE, EGL_ALPHA_SIZE }, + { GLX_DEPTH_SIZE, EGL_DEPTH_SIZE }, + { GLX_STENCIL_SIZE, EGL_STENCIL_SIZE }, + { GLX_ACCUM_RED_SIZE, 0 }, + { GLX_ACCUM_GREEN_SIZE, 0 }, + { GLX_ACCUM_BLUE_SIZE, 0 }, + { GLX_ACCUM_ALPHA_SIZE, 0 }, + { GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS }, + { GLX_SAMPLES, EGL_SAMPLES }, + { GLX_RENDER_TYPE, 0 }, + { GLX_DRAWABLE_TYPE, EGL_SURFACE_TYPE }, + { GLX_X_RENDERABLE, EGL_NATIVE_RENDERABLE }, + { GLX_X_VISUAL_TYPE, EGL_NATIVE_VISUAL_TYPE }, + { GLX_CONFIG_CAVEAT, EGL_CONFIG_CAVEAT }, + { GLX_TRANSPARENT_TYPE, EGL_TRANSPARENT_TYPE }, + { GLX_TRANSPARENT_INDEX_VALUE, 0 }, + { GLX_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_RED_VALUE }, + { GLX_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_GREEN_VALUE }, + { GLX_TRANSPARENT_BLUE_VALUE, EGL_TRANSPARENT_BLUE_VALUE }, + { GLX_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_WIDTH }, + { GLX_MAX_PBUFFER_HEIGHT, EGL_MAX_PBUFFER_HEIGHT }, + { GLX_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_PIXELS }, + { GLX_VISUAL_ID, EGL_NATIVE_VISUAL_ID } +}; + + +static EGLBoolean +convert_fbconfig(struct GLX_egl_driver *GLX_drv, + struct GLX_egl_display *GLX_dpy, GLXFBConfig fbconfig, + struct GLX_egl_config *GLX_conf) { - return (struct GLX_egl_surface *) surf; + Display *dpy = GLX_dpy->dpy; + int err, attr, val; + unsigned i; + + /* must have rgba bit */ + err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &val); + if (err || !(val & GLX_RGBA_BIT)) + return EGL_FALSE; + + /* must know whether it is double-buffered */ + err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &val); + if (err) + return EGL_FALSE; + GLX_conf->double_buffered = val; + + GLX_conf->Base.RenderableType = EGL_OPENGL_BIT; + GLX_conf->Base.Conformant = EGL_OPENGL_BIT; + + for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) { + EGLint egl_attr, egl_val; + + attr = fbconfig_attributes[i].attr; + egl_attr = fbconfig_attributes[i].egl_attr; + if (!egl_attr) + continue; + + err = GLX_drv->glXGetFBConfigAttrib(dpy, fbconfig, attr, &val); + if (err) { + if (err == GLX_BAD_ATTRIBUTE) { + err = 0; + continue; + } + break; + } + + switch (egl_attr) { + case EGL_SURFACE_TYPE: + egl_val = 0; + if (val & GLX_WINDOW_BIT) + egl_val |= EGL_WINDOW_BIT; + /* pixmap and pbuffer surfaces must be single-buffered in EGL */ + if (!GLX_conf->double_buffered) { + if (val & GLX_PIXMAP_BIT) + egl_val |= EGL_PIXMAP_BIT; + if (val & GLX_PBUFFER_BIT) + egl_val |= EGL_PBUFFER_BIT; + } + break; + case EGL_NATIVE_VISUAL_TYPE: + switch (val) { + case GLX_TRUE_COLOR: + egl_val = TrueColor; + break; + case GLX_DIRECT_COLOR: + egl_val = DirectColor; + break; + case GLX_PSEUDO_COLOR: + egl_val = PseudoColor; + break; + case GLX_STATIC_COLOR: + egl_val = StaticColor; + break; + case GLX_GRAY_SCALE: + egl_val = GrayScale; + break; + case GLX_STATIC_GRAY: + egl_val = StaticGray; + break; + default: + egl_val = EGL_NONE; + break; + } + break; + case EGL_CONFIG_CAVEAT: + egl_val = EGL_NONE; + if (val == GLX_SLOW_CONFIG) { + egl_val = EGL_SLOW_CONFIG; + } + else if (val == GLX_NON_CONFORMANT_CONFIG) { + GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT; + egl_val = EGL_NONE; + } + break; + case EGL_TRANSPARENT_TYPE: + egl_val = (val == GLX_TRANSPARENT_RGB) ? + EGL_TRANSPARENT_RGB : EGL_NONE; + break; + default: + egl_val = val; + break; + } + + _eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val); + } + if (err) + return EGL_FALSE; + + if (!GLX_conf->Base.SurfaceType) + return EGL_FALSE; + + return EGL_TRUE; } -static GLboolean -get_visual_attribs(Display *dpy, XVisualInfo *vInfo, - struct visual_attribs *attribs) +static const struct { + int attr; + int egl_attr; +} visual_attributes[] = { + /* table 3.7 of GLX 1.4 */ + { GLX_USE_GL, 0 }, + { GLX_BUFFER_SIZE, EGL_BUFFER_SIZE }, + { GLX_LEVEL, EGL_LEVEL }, + { GLX_RGBA, 0 }, + { GLX_DOUBLEBUFFER, 0 }, + { GLX_STEREO, 0 }, + { GLX_AUX_BUFFERS, 0 }, + { GLX_RED_SIZE, EGL_RED_SIZE }, + { GLX_GREEN_SIZE, EGL_GREEN_SIZE }, + { GLX_BLUE_SIZE, EGL_BLUE_SIZE }, + { GLX_ALPHA_SIZE, EGL_ALPHA_SIZE }, + { GLX_DEPTH_SIZE, EGL_DEPTH_SIZE }, + { GLX_STENCIL_SIZE, EGL_STENCIL_SIZE }, + { GLX_ACCUM_RED_SIZE, 0 }, + { GLX_ACCUM_GREEN_SIZE, 0 }, + { GLX_ACCUM_BLUE_SIZE, 0 }, + { GLX_ACCUM_ALPHA_SIZE, 0 }, + { GLX_SAMPLE_BUFFERS, EGL_SAMPLE_BUFFERS }, + { GLX_SAMPLES, EGL_SAMPLES }, + { GLX_FBCONFIG_ID, 0 }, + /* GLX_EXT_visual_rating */ + { GLX_VISUAL_CAVEAT_EXT, EGL_CONFIG_CAVEAT } +}; + +static EGLBoolean +convert_visual(struct GLX_egl_driver *GLX_drv, + struct GLX_egl_display *GLX_dpy, XVisualInfo *vinfo, + struct GLX_egl_config *GLX_conf) { - const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); - int rgba; + Display *dpy = GLX_dpy->dpy; + int err, attr, val; + unsigned i; + + /* the visual must support OpenGL and RGBA buffer */ + err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_USE_GL, &val); + if (!err && val) + err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_RGBA, &val); + if (err || !val) + return EGL_FALSE; - memset(attribs, 0, sizeof(struct visual_attribs)); + /* must know whether it is double-buffered */ + err = GLX_drv->glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &val); + if (err) + return EGL_FALSE; + GLX_conf->double_buffered = val; + + GLX_conf->Base.RenderableType = EGL_OPENGL_BIT; + GLX_conf->Base.Conformant = EGL_OPENGL_BIT; + GLX_conf->Base.SurfaceType = EGL_WINDOW_BIT; + /* pixmap surfaces must be single-buffered in EGL */ + if (!GLX_conf->double_buffered) + GLX_conf->Base.SurfaceType |= EGL_PIXMAP_BIT; + + GLX_conf->Base.NativeVisualID = vinfo->visualid; + GLX_conf->Base.NativeVisualType = vinfo->class; + GLX_conf->Base.NativeRenderable = EGL_TRUE; + + for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) { + EGLint egl_attr, egl_val; + + attr = visual_attributes[i].attr; + egl_attr = visual_attributes[i].egl_attr; + if (!egl_attr) + continue; + + err = GLX_drv->glXGetConfig(dpy, vinfo, attr, &val); + if (err) { + if (err == GLX_BAD_ATTRIBUTE) { + err = 0; + continue; + } + break; + } - 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); + switch (egl_attr) { + case EGL_CONFIG_CAVEAT: + egl_val = EGL_NONE; + if (val == GLX_SLOW_VISUAL_EXT) { + egl_val = EGL_SLOW_CONFIG; + } + else if (val == GLX_NON_CONFORMANT_VISUAL_EXT) { + GLX_conf->Base.Conformant &= ~EGL_OPENGL_BIT; + egl_val = EGL_NONE; + } + break; + break; + default: + egl_val = val; + break; + } + _eglSetConfigKey(&GLX_conf->Base, egl_attr, egl_val); } -#endif - else { - attribs->numSamples = 0; - attribs->numMultisample = 0; + + return (err) ? EGL_FALSE : EGL_TRUE; +} + + +static void +fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf) +{ + _EGLConfig *conf = &GLX_conf->Base; + + if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) { + /* some GLX impls do not like single-buffered window surface */ + conf->SurfaceType &= ~EGL_WINDOW_BIT; + /* pbuffer bit is usually not set */ + if (GLX_dpy->have_pbuffer) + conf->SurfaceType |= EGL_PBUFFER_BIT; } -#if defined(GLX_EXT_visual_rating) - if (ext && strstr(ext, "GLX_EXT_visual_rating")) { - glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); + /* no visual attribs unless window bit is set */ + if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { + conf->NativeVisualID = 0; + conf->NativeVisualType = EGL_NONE; } - else { - attribs->visualCaveat = GLX_NONE_EXT; + + if (conf->TransparentType != EGL_TRANSPARENT_RGB) { + /* some impls set them to -1 (GLX_DONT_CARE) */ + conf->TransparentRedValue = 0; + conf->TransparentGreenValue = 0; + conf->TransparentBlueValue = 0; } -#else - attribs->visualCaveat = 0; -#endif - return GL_TRUE; + /* make sure buffer size is set correctly */ + conf->BufferSize = + conf->RedSize + conf->GreenSize + conf->BlueSize + conf->AlphaSize; } + static EGLBoolean -create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv) +create_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint screen) { - XVisualInfo theTemplate; - int numVisuals; - long mask; - int i; - struct visual_attribs attribs; + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(dpy); + EGLint num_configs = 0, i; + EGLint id = 1; + + if (GLX_dpy->have_fbconfig) { + GLX_dpy->fbconfigs = + GLX_drv->glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs); + } + else { + XVisualInfo vinfo_template; + long mask; - /* get list of all visuals on this screen */ - theTemplate.screen = DefaultScreen(disp->Xdpy); - mask = VisualScreenMask; - GLX_drv->visuals = XGetVisualInfo(disp->Xdpy, mask, &theTemplate, &numVisuals); + 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; + if (!num_configs) + return EGL_FALSE; - if (!get_visual_attribs(disp->Xdpy, &GLX_drv->visuals[i], &attribs)) - continue; + for (i = 0; i < num_configs; i++) { + struct GLX_egl_config *GLX_conf, template; + EGLBoolean ok; - config = CALLOC_STRUCT(GLX_egl_config); + memset(&template, 0, sizeof(template)); + _eglInitConfig(&template.Base, dpy, id); + if (GLX_dpy->have_fbconfig) { + ok = convert_fbconfig(GLX_drv, GLX_dpy, + GLX_dpy->fbconfigs[i], &template); + } + else { + ok = convert_visual(GLX_drv, GLX_dpy, + &GLX_dpy->visuals[i], &template); + } + if (!ok) + continue; - _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*/)); + fix_config(GLX_dpy, &template); + if (!_eglValidateConfig(&template.Base, EGL_FALSE)) { + _eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i); + continue; + } - /* 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); + _eglLinkConfig(&GLX_conf->Base); + id++; + } } return EGL_TRUE; } + +static void +check_extensions(struct GLX_egl_driver *GLX_drv, + struct GLX_egl_display *GLX_dpy, EGLint screen) +{ + GLX_dpy->extensions = + GLX_drv->glXQueryExtensionsString(GLX_dpy->dpy, screen); + if (GLX_dpy->extensions) { + if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) { + /* GLX 1.3 entry points are used */ + GLX_dpy->have_make_current_read = EGL_TRUE; + } + + if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) { + /* GLX 1.3 entry points are used */ + GLX_dpy->have_fbconfig = EGL_TRUE; + } + + if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) { + if (GLX_drv->glXCreateGLXPbufferSGIX && + GLX_drv->glXDestroyGLXPbufferSGIX && + GLX_dpy->have_fbconfig) + GLX_dpy->have_pbuffer = EGL_TRUE; + } + } + + if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) { + GLX_dpy->have_1_3 = EGL_TRUE; + GLX_dpy->have_make_current_read = EGL_TRUE; + GLX_dpy->have_fbconfig = EGL_TRUE; + GLX_dpy->have_pbuffer = EGL_TRUE; + } +} + + +static void +check_quirks(struct GLX_egl_driver *GLX_drv, + 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 = GLX_drv->glXGetClientString(GLX_dpy->dpy, GLX_VENDOR); + if (vendor && strstr(vendor, "NVIDIA")) { + vendor = GLX_drv->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(). */ static EGLBoolean -GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy, - EGLint *minor, EGLint *major) +GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp, + EGLint *major, EGLint *minor) { struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); - _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct GLX_egl_display *GLX_dpy; + + if (disp->Platform != _EGL_PLATFORM_X11) + return EGL_FALSE; - _eglLog(_EGL_DEBUG, "XDRI: eglInitialize"); + GLX_dpy = CALLOC_STRUCT(GLX_egl_display); + if (!GLX_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); - if (!disp->Xdpy) { - disp->Xdpy = XOpenDisplay(NULL); - if (!disp->Xdpy) { - _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed"); + GLX_dpy->dpy = (Display *) disp->PlatformDisplay; + if (!GLX_dpy->dpy) { + GLX_dpy->dpy = XOpenDisplay(NULL); + if (!GLX_dpy->dpy) { + _eglLog(_EGL_WARNING, "GLX: XOpenDisplay failed"); + free(GLX_dpy); return EGL_FALSE; } } - GLX_drv->Base.Initialized = EGL_TRUE; + if (!GLX_drv->glXQueryVersion(GLX_dpy->dpy, + &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) { + _eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed"); + if (!disp->PlatformDisplay) + XCloseDisplay(GLX_dpy->dpy); + free(GLX_dpy); + return EGL_FALSE; + } - GLX_drv->Base.Name = "GLX"; + disp->DriverData = (void *) GLX_dpy; + disp->ClientAPIsMask = EGL_OPENGL_BIT; - /* we're supporting EGL 1.4 */ - *minor = 1; - *major = 4; + check_extensions(GLX_drv, GLX_dpy, DefaultScreen(GLX_dpy->dpy)); + check_quirks(GLX_drv, GLX_dpy, DefaultScreen(GLX_dpy->dpy)); - create_configs(disp, GLX_drv); + create_configs(drv, disp, DefaultScreen(GLX_dpy->dpy)); + if (!_eglGetArraySize(disp->Configs)) { + _eglLog(_EGL_WARNING, "GLX: failed to create any config"); + if (!disp->PlatformDisplay) + XCloseDisplay(GLX_dpy->dpy); + free(GLX_dpy); + return EGL_FALSE; + } + + /* we're supporting EGL 1.4 */ + *major = 1; + *minor = 4; return EGL_TRUE; } @@ -329,13 +640,23 @@ GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy, * Called via eglTerminate(), drv->API.Terminate(). */ static EGLBoolean -GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy) +GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); - _eglLog(_EGL_DEBUG, "XDRI: eglTerminate"); + _eglReleaseDisplayResources(drv, disp); + _eglCleanupDisplay(disp); -// XCloseDisplay(disp->Xdpy); + if (GLX_dpy->visuals) + XFree(GLX_dpy->visuals); + if (GLX_dpy->fbconfigs) + XFree(GLX_dpy->fbconfigs); + + if (!disp->PlatformDisplay) + XCloseDisplay(GLX_dpy->dpy); + free(GLX_dpy); + + disp->DriverData = NULL; return EGL_TRUE; } @@ -344,45 +665,60 @@ GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy) /** * Called via eglCreateContext(), drv->API.CreateContext(). */ -static EGLContext -GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) +static _EGLContext * +GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, + _EGLContext *share_list, const EGLint *attrib_list) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context); struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); - struct GLX_egl_context *GLX_ctx_shared = NULL; - _EGLConfig *conf; + struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_context *GLX_ctx_shared = GLX_egl_context(share_list); - if (!GLX_ctx) - return EGL_NO_CONTEXT; + if (!GLX_ctx) { + _eglError(EGL_BAD_ALLOC, "eglCreateContext"); + return NULL; + } - if (!_eglInitContext(drv, dpy, &GLX_ctx->Base, config, attrib_list)) { + if (!_eglInitContext(&GLX_ctx->Base, disp, conf, attrib_list)) { free(GLX_ctx); - return EGL_NO_CONTEXT; + return NULL; } - if (share_list != EGL_NO_CONTEXT) { - _EGLContext *shareCtx = _eglLookupContext(share_list); - if (!shareCtx) { - _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)"); - return EGL_FALSE; - } - GLX_ctx_shared = GLX_egl_context(shareCtx); + if (GLX_dpy->have_fbconfig) { + GLX_ctx->context = GLX_drv->glXCreateNewContext(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_RGBA_TYPE, + GLX_ctx_shared ? GLX_ctx_shared->context : NULL, + GL_TRUE); + } + else { + GLX_ctx->context = GLX_drv->glXCreateContext(GLX_dpy->dpy, + &GLX_dpy->visuals[GLX_egl_config_index(conf)], + GLX_ctx_shared ? GLX_ctx_shared->context : NULL, + GL_TRUE); + } + if (!GLX_ctx->context) { + free(GLX_ctx); + return NULL; } - conf = _eglLookupConfig(drv, dpy, config); - assert(conf); + return &GLX_ctx->Base; +} - GLX_ctx->context = glXCreateContext(disp->Xdpy, &GLX_drv->visuals[(int)config-1], GLX_ctx_shared ? GLX_ctx_shared->context : NULL, GL_TRUE); - if (!GLX_ctx->context) - return EGL_FALSE; - /* need to have a direct rendering context */ - if (!glXIsDirect(disp->Xdpy, GLX_ctx->context)) - return EGL_FALSE; +/** + * Destroy a surface. The display is allowed to be uninitialized. + */ +static void +destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) +{ + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + + if (GLX_surf->destroy) + GLX_surf->destroy(GLX_dpy->dpy, GLX_surf->glx_drawable); - return _eglGetContextHandle(&GLX_ctx->Base); + free(GLX_surf); } @@ -390,25 +726,58 @@ GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, * Called via eglMakeCurrent(), drv->API.MakeCurrent(). */ static EGLBoolean -GLX_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, - EGLSurface r, EGLContext context) +GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, + _EGLSurface *rsurf, _EGLContext *ctx) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - _EGLContext *ctx = _eglLookupContext(context); - _EGLSurface *dsurf = _eglLookupSurface(d); - _EGLSurface *rsurf = _eglLookupSurface(r); + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf); struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf); struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx); - - if (!_eglMakeCurrent(drv, dpy, d, r, context)) + _EGLContext *old_ctx; + _EGLSurface *old_dsurf, *old_rsurf; + GLXDrawable ddraw, rdraw; + GLXContext cctx; + EGLBoolean ret = EGL_FALSE; + + /* make new bindings */ + if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) return EGL_FALSE; -// if (!glXMakeContextCurrent(disp->Xdpy, GLX_dsurf->drawable, GLX_rsurf->drawable, GLX_ctx->context)) - if (!glXMakeCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL)) - return EGL_FALSE; + ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None; + rdraw = (GLX_rsurf) ? GLX_rsurf->glx_drawable : None; + cctx = (GLX_ctx) ? GLX_ctx->context : NULL; + + if (GLX_dpy->have_make_current_read) + ret = GLX_drv->glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx); + else if (ddraw == rdraw) + ret = GLX_drv->glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx); + + if (ret) { + if (_eglPutSurface(old_dsurf)) + destroy_surface(disp, old_dsurf); + if (_eglPutSurface(old_rsurf)) + destroy_surface(disp, old_rsurf); + /* no destroy? */ + _eglPutContext(old_ctx); + } + else { + /* undo the previous _eglBindContext */ + _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf); + assert(&GLX_ctx->Base == ctx && + &GLX_dsurf->Base == dsurf && + &GLX_rsurf->Base == rsurf); + + _eglPutSurface(dsurf); + _eglPutSurface(rsurf); + _eglPutContext(ctx); + + _eglPutSurface(old_dsurf); + _eglPutSurface(old_rsurf); + _eglPutContext(old_ctx); + } - return EGL_TRUE; + return ret; } /** Get size of given window */ @@ -428,113 +797,316 @@ get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height) /** * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). */ -static EGLSurface -GLX_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, - NativeWindowType window, const EGLint *attrib_list) +static _EGLSurface * +GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); struct GLX_egl_surface *GLX_surf; uint width, height; GLX_surf = CALLOC_STRUCT(GLX_egl_surface); - if (!GLX_surf) - return EGL_NO_SURFACE; + if (!GLX_surf) { + _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface"); + return NULL; + } - if (!_eglInitSurface(drv, dpy, &GLX_surf->Base, EGL_WINDOW_BIT, - config, attrib_list)) { + if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_WINDOW_BIT, + conf, attrib_list)) { free(GLX_surf); - return EGL_FALSE; + return NULL; } - _eglSaveSurface(&GLX_surf->Base); - GLX_surf->drawable = window; - get_drawable_size(disp->Xdpy, window, &width, &height); + + if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk) { + GLX_surf->glx_drawable = GLX_drv->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; + } + + if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk) + GLX_surf->destroy = GLX_drv->glXDestroyWindow; + + get_drawable_size(GLX_dpy->dpy, window, &width, &height); GLX_surf->Base.Width = width; GLX_surf->Base.Height = height; - return _eglGetSurfaceHandle(&GLX_surf->Base); + return &GLX_surf->Base; } -static EGLBoolean -GLX_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +static _EGLSurface * +GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativePixmapType pixmap, + const EGLint *attrib_list) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - _EGLSurface *surf = _eglLookupSurface(surface); - return EGL_TRUE; - if (surf) { - _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface); - if (surf->IsBound) { - surf->DeletePending = EGL_TRUE; + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_surface *GLX_surf; + uint width, height; + + GLX_surf = CALLOC_STRUCT(GLX_egl_surface); + if (!GLX_surf) { + _eglError(EGL_BAD_ALLOC, "eglCreatePixmapSurface"); + return NULL; + } + + if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PIXMAP_BIT, + conf, attrib_list)) { + free(GLX_surf); + return NULL; + } + + GLX_surf->drawable = pixmap; + + if (GLX_dpy->have_1_3) { + GLX_surf->glx_drawable = GLX_drv->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; + + vinfo = GLX_drv->glXGetVisualFromFBConfig(GLX_dpy->dpy, fbconfig); + if (vinfo) { + GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPixmap(GLX_dpy->dpy, + vinfo, GLX_surf->drawable); + XFree(vinfo); } - else { - free(surf); + } + else { + GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPixmap(GLX_dpy->dpy, + &GLX_dpy->visuals[GLX_egl_config_index(conf)], + GLX_surf->drawable); + } + + if (!GLX_surf->glx_drawable) { + free(GLX_surf); + return NULL; + } + + GLX_surf->destroy = (GLX_dpy->have_1_3) ? + GLX_drv->glXDestroyPixmap : GLX_drv->glXDestroyGLXPixmap; + + get_drawable_size(GLX_dpy->dpy, pixmap, &width, &height); + GLX_surf->Base.Width = width; + GLX_surf->Base.Height = height; + + return &GLX_surf->Base; +} + +static _EGLSurface * +GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, const EGLint *attrib_list) +{ + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_surface *GLX_surf; + int attribs[5]; + int i; + + GLX_surf = CALLOC_STRUCT(GLX_egl_surface); + if (!GLX_surf) { + _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface"); + return NULL; + } + + if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PBUFFER_BIT, + conf, attrib_list)) { + free(GLX_surf); + return NULL; + } + + 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; } + attribs[i] = None; - return EGL_TRUE; + GLX_surf->glx_drawable = GLX_drv->glXCreatePbuffer(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], attribs); } - else { - _eglError(EGL_BAD_SURFACE, "eglDestroySurface"); - return EGL_FALSE; + else if (GLX_dpy->have_pbuffer) { + GLX_surf->glx_drawable = GLX_drv->glXCreateGLXPbufferSGIX(GLX_dpy->dpy, + GLX_dpy->fbconfigs[GLX_egl_config_index(conf)], + GLX_surf->Base.Width, + GLX_surf->Base.Height, + attribs); + } + + if (!GLX_surf->glx_drawable) { + free(GLX_surf); + return NULL; } + + GLX_surf->destroy = (GLX_dpy->have_1_3) ? + GLX_drv->glXDestroyPbuffer : GLX_drv->glXDestroyGLXPbufferSGIX; + + return &GLX_surf->Base; } static EGLBoolean -GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, - EGLint buffer) +GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - _EGLSurface *surf = _eglLookupSurface(surface); - struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + (void) drv; - /* buffer ?? */ - glXBindTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT, NULL); + if (_eglPutSurface(surf)) + destroy_surface(disp, surf); return EGL_TRUE; } static EGLBoolean -GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, - EGLint buffer) +GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - _EGLSurface *surf = _eglLookupSurface(surface); - struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp); + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw); - /* buffer ?? */ - glXReleaseTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT); + GLX_drv->glXSwapBuffers(GLX_dpy->dpy, GLX_surf->glx_drawable); return EGL_TRUE; } +/* + * Called from eglGetProcAddress() via drv->API.GetProcAddress(). + */ +static _EGLProc +GLX_eglGetProcAddress(_EGLDriver *drv, const char *procname) +{ + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + + return (_EGLProc) GLX_drv->glXGetProcAddress((const GLubyte *) procname); +} static EGLBoolean -GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) +GLX_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) { - _EGLDisplay *disp = _eglLookupDisplay(dpy); - _EGLSurface *surf = _eglLookupSurface(draw); - struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); - _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers 0x%x",draw); + (void) dpy; + (void) ctx; - /* error checking step: */ - if (!_eglSwapBuffers(drv, dpy, draw)) - return EGL_FALSE; + GLX_drv->glXWaitGL(); + return EGL_TRUE; +} + +static EGLBoolean +GLX_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) +{ + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); - glXSwapBuffers(disp->Xdpy, GLX_surf->drawable); + (void) dpy; + if (engine != EGL_CORE_NATIVE_ENGINE) + return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); + GLX_drv->glXWaitX(); return EGL_TRUE; } -/* - * Called from eglGetProcAddress() via drv->API.GetProcAddress(). - */ -static _EGLProc -GLX_eglGetProcAddress(const char *procname) +static void +GLX_Unload(_EGLDriver *drv) +{ + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + + if (GLX_drv->handle) + dlclose(GLX_drv->handle); + free(GLX_drv); +} + + +static EGLBoolean +GLX_Load(_EGLDriver *drv) { - return (_EGLProc)glXGetProcAddress((const GLubyte *)procname); + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + void *handle; + + handle = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL); + if (!handle) + goto fail; + + GLX_drv->glXGetProcAddress = dlsym(handle, "glXGetProcAddress"); + if (!GLX_drv->glXGetProcAddress) + GLX_drv->glXGetProcAddress = dlsym(handle, "glXGetProcAddressARB"); + if (!GLX_drv->glXGetProcAddress) + goto fail; + +#define GET_PROC(proc_type, proc_name, check) \ + do { \ + GLX_drv->proc_name = (proc_type) \ + GLX_drv->glXGetProcAddress((const GLubyte *) #proc_name); \ + if (check && !GLX_drv->proc_name) goto fail; \ + } while (0) + + /* GLX 1.0 */ + GET_PROC(GLXCREATECONTEXTPROC, glXCreateContext, EGL_TRUE); + GET_PROC(GLXDESTROYCONTEXTPROC, glXDestroyContext, EGL_TRUE); + GET_PROC(GLXMAKECURRENTPROC, glXMakeCurrent, EGL_TRUE); + GET_PROC(GLXSWAPBUFFERSPROC, glXSwapBuffers, EGL_TRUE); + GET_PROC(GLXCREATEGLXPIXMAPPROC, glXCreateGLXPixmap, EGL_TRUE); + GET_PROC(GLXDESTROYGLXPIXMAPPROC, glXDestroyGLXPixmap, EGL_TRUE); + GET_PROC(GLXQUERYVERSIONPROC, glXQueryVersion, EGL_TRUE); + GET_PROC(GLXGETCONFIGPROC, glXGetConfig, EGL_TRUE); + GET_PROC(GLXWAITGLPROC, glXWaitGL, EGL_TRUE); + GET_PROC(GLXWAITXPROC, glXWaitX, EGL_TRUE); + + /* GLX 1.1 */ + GET_PROC(GLXQUERYEXTENSIONSSTRINGPROC, glXQueryExtensionsString, EGL_TRUE); + GET_PROC(GLXQUERYSERVERSTRINGPROC, glXQueryServerString, EGL_TRUE); + GET_PROC(GLXGETCLIENTSTRINGPROC, glXGetClientString, EGL_TRUE); + + /* GLX 1.3 */ + GET_PROC(PFNGLXGETFBCONFIGSPROC, glXGetFBConfigs, EGL_FALSE); + GET_PROC(PFNGLXGETFBCONFIGATTRIBPROC, glXGetFBConfigAttrib, EGL_FALSE); + GET_PROC(PFNGLXGETVISUALFROMFBCONFIGPROC, glXGetVisualFromFBConfig, EGL_FALSE); + GET_PROC(PFNGLXCREATEWINDOWPROC, glXCreateWindow, EGL_FALSE); + GET_PROC(PFNGLXDESTROYWINDOWPROC, glXDestroyWindow, EGL_FALSE); + GET_PROC(PFNGLXCREATEPIXMAPPROC, glXCreatePixmap, EGL_FALSE); + GET_PROC(PFNGLXDESTROYPIXMAPPROC, glXDestroyPixmap, EGL_FALSE); + GET_PROC(PFNGLXCREATEPBUFFERPROC, glXCreatePbuffer, EGL_FALSE); + GET_PROC(PFNGLXDESTROYPBUFFERPROC, glXDestroyPbuffer, EGL_FALSE); + GET_PROC(PFNGLXCREATENEWCONTEXTPROC, glXCreateNewContext, EGL_FALSE); + GET_PROC(PFNGLXMAKECONTEXTCURRENTPROC, glXMakeContextCurrent, EGL_FALSE); + + /* GLX_SGIX_pbuffer */ + GET_PROC(PFNGLXCREATEGLXPBUFFERSGIXPROC, + glXCreateGLXPbufferSGIX, EGL_FALSE); + GET_PROC(PFNGLXDESTROYGLXPBUFFERSGIXPROC, + glXDestroyGLXPbufferSGIX, EGL_FALSE); +#undef GET_PROC + + GLX_drv->handle = handle; + + return EGL_TRUE; + +fail: + if (handle) + dlclose(handle); + return EGL_FALSE; } @@ -543,42 +1115,37 @@ GLX_eglGetProcAddress(const char *procname) * Create a new _EGLDriver object and init its dispatch table. */ _EGLDriver * -_eglMain(_EGLDisplay *disp, const char *args) +_EGL_MAIN(const char *args) { struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver); - char *env; + + (void) args; if (!GLX_drv) return NULL; + if (!GLX_Load(&GLX_drv->Base)) { + _eglLog(_EGL_WARNING, "GLX: failed to load GLX"); + free(GLX_drv); + return NULL; + } + _eglInitDriverFallbacks(&GLX_drv->Base); GLX_drv->Base.API.Initialize = GLX_eglInitialize; GLX_drv->Base.API.Terminate = GLX_eglTerminate; GLX_drv->Base.API.CreateContext = GLX_eglCreateContext; GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent; GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface; + GLX_drv->Base.API.CreatePixmapSurface = GLX_eglCreatePixmapSurface; + GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface; 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.ClientAPIsMask = all_apis; GLX_drv->Base.Name = "GLX"; - - _eglLog(_EGL_DEBUG, "GLX: main(%s)", args); - - /* set new DRI path to pick up EGL version (which doesn't contain any mesa - * code), but don't override if one is already set. - */ - env = getenv("LIBGL_DRIVERS_PATH"); - if (env) { - if (!strstr(env, "egl")) { - sprintf(env, "%s/egl", env); - setenv("LIBGL_DRIVERS_PATH", env, 1); - } - } else - setenv("LIBGL_DRIVERS_PATH", DEFAULT_DRIVER_DIR"/egl", 0); + GLX_drv->Base.Unload = GLX_Unload; return &GLX_drv->Base; }