diff options
Diffstat (limited to 'src/egl')
38 files changed, 3542 insertions, 633 deletions
diff --git a/src/egl/Makefile b/src/egl/Makefile index fb4db8f9b9..024453f8bb 100644 --- a/src/egl/Makefile +++ b/src/egl/Makefile @@ -2,7 +2,7 @@ TOP = ../.. -SUBDIRS = main drivers/demo drivers/dri +SUBDIRS = main drivers default: subdirs diff --git a/src/egl/drivers/Makefile b/src/egl/drivers/Makefile new file mode 100644 index 0000000000..f0538f563f --- /dev/null +++ b/src/egl/drivers/Makefile @@ -0,0 +1,25 @@ +# src/egl/drivers/Makefile + +TOP = ../../.. +include $(TOP)/configs/current + +SUBDIRS = $(EGL_DRIVERS_DIRS) + + +default: subdirs + + +subdirs: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir ; $(MAKE)) || exit 1 ; \ + fi \ + done + + +clean: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir ; $(MAKE) clean) ; \ + fi \ + done diff --git a/src/egl/drivers/demo/demo.c b/src/egl/drivers/demo/demo.c index 45545755c0..1750e976b8 100644 --- a/src/egl/drivers/demo/demo.c +++ b/src/egl/drivers/demo/demo.c @@ -21,7 +21,7 @@ typedef struct demo_driver { _EGLDriver Base; /* base class/object */ - GLuint DemoStuff; + unsigned DemoStuff; } DemoDriver; #define DEMO_DRIVER(D) ((DemoDriver *) (D)) @@ -33,7 +33,7 @@ typedef struct demo_driver typedef struct demo_surface { _EGLSurface Base; /* base class/object */ - GLuint DemoStuff; + unsigned DemoStuff; } DemoSurface; @@ -43,7 +43,7 @@ typedef struct demo_surface typedef struct demo_context { _EGLContext Base; /* base class/object */ - GLuint DemoStuff; + unsigned DemoStuff; } DemoContext; @@ -67,22 +67,22 @@ demoInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor) /* Create the display's visual configs - silly example */ for (i = 0; i < 4; i++) { - _EGLConfig config; - _eglInitConfig(&config, i + 1); - _eglSetConfigAttrib(&config, EGL_RED_SIZE, 8); - _eglSetConfigAttrib(&config, EGL_GREEN_SIZE, 8); - _eglSetConfigAttrib(&config, EGL_BLUE_SIZE, 8); - _eglSetConfigAttrib(&config, EGL_ALPHA_SIZE, 8); - _eglSetConfigAttrib(&config, EGL_BUFFER_SIZE, 32); + _EGLConfig *config = calloc(1, sizeof(_EGLConfig)); + _eglInitConfig(config, i + 1); + _eglSetConfigAttrib(config, EGL_RED_SIZE, 8); + _eglSetConfigAttrib(config, EGL_GREEN_SIZE, 8); + _eglSetConfigAttrib(config, EGL_BLUE_SIZE, 8); + _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, 8); + _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, 32); if (i & 1) { - _eglSetConfigAttrib(&config, EGL_DEPTH_SIZE, 32); + _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, 32); } if (i & 2) { - _eglSetConfigAttrib(&config, EGL_STENCIL_SIZE, 8); + _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, 8); } - _eglSetConfigAttrib(&config, EGL_SURFACE_TYPE, + _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, (EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)); - _eglAddConfig(disp, &config); + _eglAddConfig(disp, config); } drv->Initialized = EGL_TRUE; @@ -152,9 +152,9 @@ demoCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext /* generate handle and insert into hash table */ _eglSaveContext(&c->Base); - assert(c->Base.Handle); + assert(_eglGetContextHandle(&c->Base)); - return c->Base.Handle; + return _eglGetContextHandle(&c->Base); } @@ -286,7 +286,7 @@ demoMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface rea * plug in API functions. */ _EGLDriver * -_eglMain(_EGLDisplay *dpy) +_eglMain(_EGLDisplay *dpy, const char *args) { DemoDriver *demo; diff --git a/src/egl/drivers/dri/Makefile b/src/egl/drivers/dri/Makefile index af0c40fe2b..d7eba653b2 100644 --- a/src/egl/drivers/dri/Makefile +++ b/src/egl/drivers/dri/Makefile @@ -8,7 +8,7 @@ include $(TOP)/configs/current INCLUDE_DIRS = \ -I. \ -I/usr/include \ - -I/usr/include/drm \ + $(shell pkg-config --cflags-only-I libdrm) \ -I$(TOP)/include \ -I$(TOP)/include/GL/internal \ -I$(TOP)/src/mesa \ @@ -29,6 +29,8 @@ SOURCES = egldri.c OBJECTS = $(SOURCES:.c=.o) +DRM_LIB = `pkg-config --libs libdrm` + .c.o: $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ @@ -44,7 +46,7 @@ library: $(TOP)/$(LIB_DIR)/libEGLdri.so $(TOP)/$(LIB_DIR)/libEGLdri.so: $(OBJECTS) $(MKLIB) -o EGLdri -linker '$(CC)' -ldflags '$(LDFLAGS)' \ -major 1 -minor 0 \ - -install $(TOP)/$(LIB_DIR) -ldl $(OBJECTS) + -install $(TOP)/$(LIB_DIR) -ldl $(OBJECTS) $(LIBS) clean: @@ -53,9 +55,10 @@ clean: depend: $(SOURCES) $(HEADERS) @ echo "running $(MKDEP)" + @ rm -f depend @ touch depend $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ - $(SOURCES) $(HEADERS) > /dev/null + $(SOURCES) $(HEADERS) >/dev/null 2>/dev/null include depend # DO NOT DELETE diff --git a/src/egl/drivers/dri/egldri.c b/src/egl/drivers/dri/egldri.c index cab0be2bd1..57661cc3ab 100644 --- a/src/egl/drivers/dri/egldri.c +++ b/src/egl/drivers/dri/egldri.c @@ -1,5 +1,6 @@ /** - * Generic EGL driver for DRI. + * Generic EGL driver for DRI. This is basically an "adaptor" driver + * that allows libEGL to load/use regular DRI drivers. * * This file contains all the code needed to interface DRI-based drivers * with libEGL. @@ -23,6 +24,7 @@ #include "egldisplay.h" #include "eglcontext.h" #include "eglconfig.h" +#include "eglconfigutil.h" #include "eglsurface.h" #include "eglscreen.h" #include "eglglobals.h" @@ -32,18 +34,72 @@ #include "egldri.h" const char *sysfs = "/sys/class"; -#define None 0 + static const int empty_attribute_list[1] = { None }; + +/** + * Given a card number, return the name of the DRI driver to use. + * This generally means reading the contents of + * /sys/class/drm/cardX/dri_library_name, where X is the card number + */ +static EGLBoolean +driver_name_from_card_number(int card, char *driverName, int maxDriverName) +{ + char path[2000]; + FILE *f; + int length; + + snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", sysfs, card); + + f = fopen(path, "r"); + if (!f) + return EGL_FALSE; + + fgets(driverName, maxDriverName, f); + fclose(f); + + if ((length = strlen(driverName)) > 1) { + /* remove the trailing newline from sysfs */ + driverName[length - 1] = '\0'; + strncat(driverName, "_dri", maxDriverName); + return EGL_TRUE; + } + else { + return EGL_FALSE; + } +} + + + /** * The bootstrap function. * Return a new driDriver object and plug in API functions. * This function, in turn, loads a specific DRI driver (ex: r200_dri.so). */ _EGLDriver * -_eglMain(_EGLDisplay *dpy) +_eglMain(_EGLDisplay *dpy, const char *args) { +#if 1 + const int card = args ? atoi(args) : 0; + _EGLDriver *driver = NULL; + char driverName[1000]; + + if (!driver_name_from_card_number(card, driverName, sizeof(driverName))) { + _eglLog(_EGL_WARNING, + "Unable to determine driver name for card %d\n", card); + return NULL; + } + + _eglLog(_EGL_DEBUG, "Driver name: %s\n", driverName); + + driver = _eglOpenDriver(dpy, driverName, args); + + return driver; + +#else + int length; char path[NAME_MAX]; struct dirent *dirent; @@ -58,14 +114,19 @@ _eglMain(_EGLDisplay *dpy) _eglLog(_EGL_WARNING, "%s DRM devices not found.", path); return EGL_FALSE; } + + /* loop over dir entries looking for cardX where "X" is in the + * dpy->DriverName ":X" string. + */ while ((dirent = readdir(dir))) { if (strncmp(&dirent->d_name[0], "card", 4) != 0) continue; - if (strcmp(&dirent->d_name[4], &dpy->Name[1]) != 0) + if (strcmp(&dirent->d_name[4], &driverName[1]) != 0) continue; - snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name", sysfs, &dpy->Name[1]); + snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name", + sysfs, &driverName[1]); _eglLog(_EGL_INFO, "Opening %s", path); #if 1 file = fopen(path, "r"); @@ -89,6 +150,7 @@ _eglMain(_EGLDisplay *dpy) closedir(dir); return driver; +#endif } @@ -141,7 +203,7 @@ _eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, /* generate handle and insert into hash table */ _eglSaveContext(&c->Base); - return c->Base.Handle; + return _eglGetContextHandle(&c->Base); } @@ -152,13 +214,15 @@ _eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, driDisplay *disp = Lookup_driDisplay(dpy); driContext *ctx = Lookup_driContext(context); EGLBoolean b; + __DRIid drawBuf = (__DRIid) draw; + __DRIid readBuf = (__DRIid) read; b = _eglMakeCurrent(drv, dpy, draw, read, context); if (!b) return EGL_FALSE; if (ctx) { - ctx->driContext.bindContext(disp, 0, read, draw, &ctx->driContext); + ctx->driContext.bindContext(disp, 0, drawBuf, readBuf, &ctx->driContext); } else { /* what's this??? */ @@ -190,7 +254,7 @@ _eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, #if 0 GLcontext *ctx = NULL; /* this _should_ be OK */ #endif - GLvisual visMode; + __GLcontextModes visMode; _EGLConfig *conf = _eglLookupConfig(drv, dpy, config); assert(conf); /* bad config should be caught earlier */ _eglConfigToContextModesRec(conf, &visMode); @@ -267,7 +331,8 @@ _eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg, _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg); driDisplay *disp = Lookup_driDisplay(dpy); driSurface *surface; - GLvisual visMode; + __GLcontextModes visMode; + __DRIid drawBuf; surface = (driSurface *) calloc(1, sizeof(*surface)); if (!surface) { @@ -292,8 +357,10 @@ _eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg, /* convert EGLConfig to GLvisual */ _eglConfigToContextModesRec(config, &visMode); + drawBuf = (__DRIid) _eglGetSurfaceHandle(&surface->Base); + /* Create a new DRI drawable */ - if (!disp->driScreen.createNewDrawable(disp, &visMode, surface->Base.Handle, + if (!disp->driScreen.createNewDrawable(disp, &visMode, drawBuf, &surface->drawable, GLX_WINDOW_BIT, empty_attribute_list)) { _eglRemoveSurface(&surface->Base); @@ -715,7 +782,7 @@ __eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable, { __DRIscreen *pDRIScreen; __DRIscreenPrivate *psp; - driSurface *surf = Lookup_driSurface(drawable); + driSurface *surf = Lookup_driSurface((EGLSurface) drawable); pDRIScreen = __eglFindDRIScreen(ndpy, screen); @@ -1019,8 +1086,10 @@ _eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer) api_ver, & interface_methods, NULL); - if (!dpy->driScreen.private) + if (!dpy->driScreen.private) { + _eglLog(_EGL_WARNING, "egldri.c: DRI create new screen failed"); return EGL_FALSE; + } DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext ); @@ -1080,6 +1149,7 @@ _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, { _EGLDisplay *disp = _eglLookupDisplay(dpy); driDisplay *display; + const char *driverName = (const char *) disp->NativeDisplay; assert(disp); @@ -1088,13 +1158,13 @@ _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, */ display = calloc(1, sizeof(*display)); display->Base = *disp; - _eglHashInsert(_eglGlobal.Displays, disp->Handle, display); + _eglSaveDisplay(&display->Base); free(disp); *major = 1; *minor = 0; - sscanf(&disp->Name[1], "%d", &display->minor); + sscanf(driverName + 1, "%d", &display->minor); drv->Initialized = EGL_TRUE; return EGL_TRUE; diff --git a/src/egl/drivers/dri/egldri.h b/src/egl/drivers/dri/egldri.h index 34b12d64fc..54a9a4ea26 100644 --- a/src/egl/drivers/dri/egldri.h +++ b/src/egl/drivers/dri/egldri.h @@ -1,11 +1,14 @@ #ifndef EGLDRI_INCLUDED #define EGLDRI_INCLUDED +#include <stdlib.h> +#include <string.h> +#include <stdint.h> #include "egldisplay.h" #include "eglscreen.h" #include "eglsurface.h" #include "eglcontext.h" -#include "mtypes.h" + #include "dri_util.h" #include "drm_sarea.h" @@ -14,7 +17,7 @@ */ typedef struct dri_display { - _EGLDisplay Base; /* base class/object */ + _EGLDisplay Base; /**< base class */ void *pFB; int drmFD; /**< \brief DRM device file descriptor */ int minor; @@ -32,7 +35,7 @@ typedef struct dri_display unsigned long FBStart; /**< \brief physical address of the framebuffer */ void *driverClientMsg; int driverClientMsgSize; - int chipset; + unsigned chipset; void *driverPrivate; drm_magic_t magic; diff --git a/src/egl/drivers/glx/Makefile b/src/egl/drivers/glx/Makefile new file mode 100644 index 0000000000..3cd5276513 --- /dev/null +++ b/src/egl/drivers/glx/Makefile @@ -0,0 +1,74 @@ +# src/egl/drivers/glx/Makefile + +# Build XEGL DRI driver loader library: egl_glx.so + + +TOP = ../../../.. +include $(TOP)/configs/current + + +EXTRA_DEFINES = -DDEFAULT_DRIVER_DIR=\"$(DRI_DRIVER_SEARCH_DIR)\" + +DRIVER_NAME = egl_glx.so + + +INCLUDE_DIRS = \ + -I. \ + -I/usr/include \ + $(shell pkg-config --cflags-only-I libdrm) \ + -I$(TOP)/include \ + -I$(TOP)/include/GL/internal \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/egl/main \ + -I$(TOP)/src/glx/x11 + +SOURCES = egl_glx.c + +OBJECTS = $(SOURCES:.c=.o) + +DRM_LIB = `pkg-config --libs libdrm` + +MISC_LIBS = -ldl -lXext -lGL + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(EXTRA_DEFINES) $< -o $@ + + +.PHONY: library + + +default: depend library Makefile + + +library: $(TOP)/$(LIB_DIR)/$(DRIVER_NAME) + + +# Make the egl_glx.so library +$(TOP)/$(LIB_DIR)/$(DRIVER_NAME): $(OBJECTS) + $(TOP)/bin/mklib -o $(DRIVER_NAME) \ + -noprefix \ + -major 1 -minor 0 \ + -L$(TOP)/$(LIB_DIR) \ + -install $(TOP)/$(LIB_DIR) \ + $(OBJECTS) $(DRM_LIB) $(MISC_LIBS) + + +clean: + rm -f *.o + rm -f *.so + rm -f depend depend.bak + + +depend: $(SOURCES) $(HEADERS) + @ echo "running $(MKDEP)" + @ rm -f depend + @ touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ + $(SOURCES) $(HEADERS) >/dev/null 2>/dev/null + +include depend +# DO NOT DELETE diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c new file mode 100644 index 0000000000..9a421b5a80 --- /dev/null +++ b/src/egl/drivers/glx/egl_glx.c @@ -0,0 +1,584 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * This is an EGL driver that wraps GLX. This gives the benefit of being + * completely agnostic of the direct rendering implementation. + * + * Authors: Alan Hourihane <alanh@tungstengraphics.com> + */ + +/* + * TODO: + * + * Add GLXFBConfig support + * Pbuffer & Pixmap support + * test eglBind/ReleaseTexImage + */ + + +#include <assert.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "dlfcn.h" +#include <X11/Xlib.h> +#include <GL/gl.h> +#include "glxclient.h" + +#define _EGL_PLATFORM_X + +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "eglhash.h" +#include "egllog.h" +#include "eglsurface.h" + +#include <GL/gl.h> + +#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 */ + +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 +{ + _EGLDriver Base; /**< base class */ + + XVisualInfo *visuals; + + /* GLXFBConfig *fbconfigs - todo */ +}; + + +/** subclass of _EGLContext */ +struct GLX_egl_context +{ + _EGLContext Base; /**< base class */ + + GLXContext context; +}; + + +/** subclass of _EGLSurface */ +struct GLX_egl_surface +{ + _EGLSurface Base; /**< base class */ + + GLXDrawable drawable; +}; + + +/** subclass of _EGLConfig */ +struct GLX_egl_config +{ + _EGLConfig Base; /**< base class */ +}; + +/** cast wrapper */ +static struct GLX_egl_driver * +GLX_egl_driver(_EGLDriver *drv) +{ + return (struct GLX_egl_driver *) drv; +} + +static struct GLX_egl_context * +GLX_egl_context(_EGLContext *ctx) +{ + return (struct GLX_egl_context *) ctx; +} + +static struct GLX_egl_surface * +GLX_egl_surface(_EGLSurface *surf) +{ + return (struct GLX_egl_surface *) surf; +} + +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)); + + 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; + } +#else + attribs->visualCaveat = 0; +#endif + + return GL_TRUE; +} + +static EGLBoolean +create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv) +{ + XVisualInfo theTemplate; + int numVisuals; + long mask; + int i; + struct visual_attribs attribs; + + /* get list of all visuals on this screen */ + theTemplate.screen = DefaultScreen(disp->Xdpy); + mask = VisualScreenMask; + GLX_drv->visuals = XGetVisualInfo(disp->Xdpy, mask, &theTemplate, &numVisuals); + + for (i = 0; i < numVisuals; i++) { + struct GLX_egl_config *config; + + if (!get_visual_attribs(disp->Xdpy, &GLX_drv->visuals[i], &attribs)) + continue; + + config = CALLOC_STRUCT(GLX_egl_config); + + _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*/)); + + /* XXX possibly other things to init... */ + + _eglAddConfig(disp, &config->Base); + } + + return EGL_TRUE; +} + +/** + * Called via eglInitialize(), GLX_drv->API.Initialize(). + */ +static EGLBoolean +GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy, + EGLint *minor, EGLint *major) +{ + struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv); + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + _eglLog(_EGL_DEBUG, "XDRI: eglInitialize"); + + if (!disp->Xdpy) { + disp->Xdpy = XOpenDisplay(NULL); + if (!disp->Xdpy) { + _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed"); + return EGL_FALSE; + } + } + + GLX_drv->Base.Initialized = EGL_TRUE; + + GLX_drv->Base.Name = "GLX"; + + /* we're supporting EGL 1.4 */ + *minor = 1; + *major = 4; + + create_configs(disp, GLX_drv); + + return EGL_TRUE; +} + + +/** + * Called via eglTerminate(), drv->API.Terminate(). + */ +static EGLBoolean +GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + _eglLog(_EGL_DEBUG, "XDRI: eglTerminate"); + +// XCloseDisplay(disp->Xdpy); + + return EGL_TRUE; +} + + +/** + * Called via eglCreateContext(), drv->API.CreateContext(). + */ +static EGLContext +GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + 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; + + if (!GLX_ctx) + return EGL_NO_CONTEXT; + + if (!_eglInitContext(drv, dpy, &GLX_ctx->Base, config, attrib_list)) { + free(GLX_ctx); + return EGL_NO_CONTEXT; + } + + 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); + } + + conf = _eglLookupConfig(drv, dpy, config); + assert(conf); + + 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; + + return _eglGetContextHandle(&GLX_ctx->Base); +} + + +/** + * Called via eglMakeCurrent(), drv->API.MakeCurrent(). + */ +static EGLBoolean +GLX_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, + EGLSurface r, EGLContext context) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLContext *ctx = _eglLookupContext(context); + _EGLSurface *dsurf = _eglLookupSurface(d); + _EGLSurface *rsurf = _eglLookupSurface(r); + 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)) + 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; + + return EGL_TRUE; +} + +/** Get size of given window */ +static Status +get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height) +{ + Window root; + Status stat; + int xpos, ypos; + unsigned int w, h, bw, depth; + stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); + *width = w; + *height = h; + return stat; +} + +/** + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). + */ +static EGLSurface +GLX_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + NativeWindowType window, const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct GLX_egl_surface *GLX_surf; + uint width, height; + + GLX_surf = CALLOC_STRUCT(GLX_egl_surface); + if (!GLX_surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, &GLX_surf->Base, EGL_WINDOW_BIT, + config, attrib_list)) { + free(GLX_surf); + return EGL_FALSE; + } + + _eglSaveSurface(&GLX_surf->Base); + + GLX_surf->drawable = window; + get_drawable_size(disp->Xdpy, window, &width, &height); + GLX_surf->Base.Width = width; + GLX_surf->Base.Height = height; + + return _eglGetSurfaceHandle(&GLX_surf->Base); +} + +static EGLBoolean +GLX_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +{ + _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; + } + else { + free(surf); + } + + return EGL_TRUE; + } + else { + _eglError(EGL_BAD_SURFACE, "eglDestroySurface"); + return EGL_FALSE; + } +} + + +static EGLBoolean +GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, + EGLint buffer) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(surface); + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + + /* buffer ?? */ + glXBindTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT, NULL); + + return EGL_TRUE; +} + + +static EGLBoolean +GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, + EGLint buffer) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(surface); + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + + /* buffer ?? */ + glXReleaseTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT); + + return EGL_TRUE; +} + + +static EGLBoolean +GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + _EGLSurface *surf = _eglLookupSurface(draw); + struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf); + + _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers 0x%x",draw); + + /* error checking step: */ + if (!_eglSwapBuffers(drv, dpy, draw)) + return EGL_FALSE; + + glXSwapBuffers(disp->Xdpy, GLX_surf->drawable); + + return EGL_TRUE; +} + +/* + * Called from eglGetProcAddress() via drv->API.GetProcAddress(). + */ +static _EGLProc +GLX_eglGetProcAddress(const char *procname) +{ + return (_EGLProc)glXGetProcAddress((const GLubyte *)procname); +} + + +/** + * This is the main entrypoint into the driver, called by libEGL. + * Create a new _EGLDriver object and init its dispatch table. + */ +_EGLDriver * +_eglMain(_EGLDisplay *disp, const char *args) +{ + struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver); + char *env; + + if (!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.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.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); + + return &GLX_drv->Base; +} diff --git a/src/egl/drivers/xdri/Makefile b/src/egl/drivers/xdri/Makefile new file mode 100644 index 0000000000..a721b997e6 --- /dev/null +++ b/src/egl/drivers/xdri/Makefile @@ -0,0 +1,70 @@ +# src/egl/drivers/xdri/Makefile + +# Build XEGL DRI driver loader library: egl_xdri.so + + +TOP = ../../../.. +include $(TOP)/configs/current + + +DRIVER_NAME = egl_xdri.so + + +INCLUDE_DIRS = \ + -I. \ + -I/usr/include \ + $(shell pkg-config --cflags-only-I libdrm) \ + -I$(TOP)/include \ + -I$(TOP)/include/GL/internal \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/egl/main \ + -I$(TOP)/src/glx/x11 + +SOURCES = egl_xdri.c + +OBJECTS = $(SOURCES:.c=.o) + +DRM_LIB = `pkg-config --libs libdrm` + +MISC_LIBS = -ldl -lXext -lGL + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + +.PHONY: library + + +default: depend library Makefile + + +library: $(TOP)/$(LIB_DIR)/$(DRIVER_NAME) + + +# Make the egl_xdri.so library +$(TOP)/$(LIB_DIR)/$(DRIVER_NAME): $(OBJECTS) + $(TOP)/bin/mklib -o $(DRIVER_NAME) \ + -noprefix \ + -major 1 -minor 0 \ + -L$(TOP)/$(LIB_DIR) \ + -install $(TOP)/$(LIB_DIR) \ + $(OBJECTS) $(DRM_LIB) $(MISC_LIBS) + + +clean: + rm -f *.o + rm -f *.so + rm -f depend depend.bak + + +depend: $(SOURCES) $(HEADERS) + @ echo "running $(MKDEP)" + @ rm -f depend + @ touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ + $(SOURCES) $(HEADERS) >/dev/null 2>/dev/null + +include depend +# DO NOT DELETE diff --git a/src/egl/drivers/xdri/egl_xdri.c b/src/egl/drivers/xdri/egl_xdri.c new file mode 100644 index 0000000000..3b3e312746 --- /dev/null +++ b/src/egl/drivers/xdri/egl_xdri.c @@ -0,0 +1,1177 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * Code to interface a DRI driver to libEGL. + * Note that unlike previous DRI/EGL interfaces, this one is meant to + * be used _with_ X. Applications will use eglCreateWindowSurface() + * to render into X-created windows. + * + * This is an EGL driver that, in turn, loads a regular DRI driver. + * There are some dependencies on code in libGL, but those could be + * removed with some effort. + * + * Authors: Brian Paul + */ + + +#include <assert.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "dlfcn.h" +#include <X11/Xlib.h> +#include <GL/gl.h> +#include "xf86dri.h" +#include "glxclient.h" +#include "dri_util.h" +#include "drm_sarea.h" + +#define _EGL_PLATFORM_X + +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "eglhash.h" +#include "egllog.h" +#include "eglsurface.h" + +#include <GL/gl.h> + +typedef void (*glGetIntegerv_t)(GLenum, GLint *); +typedef void (*glBindTexture_t)(GLenum, GLuint); +typedef void (*glCopyTexImage2D_t)(GLenum, GLint, GLenum, GLint, GLint, + GLint, GLint, GLint); + + +#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T)) + + +/** subclass of _EGLDriver */ +struct xdri_egl_driver +{ + _EGLDriver Base; /**< base class */ + + const char *dri_driver_name; /**< name of DRI driver to load */ + void *dri_driver_handle; /**< returned by dlopen(dri_driver_name) */ + + __GLXdisplayPrivate *glx_priv; + + + /* XXX we're not actually using these at this time: */ + int chipset; + int minor; + int drmFD; + + __DRIframebuffer framebuffer; + drm_handle_t hSAREA; + drmAddress pSAREA; + char *busID; + drm_magic_t magic; +}; + + +/** subclass of _EGLContext */ +struct xdri_egl_context +{ + _EGLContext Base; /**< base class */ + + __DRIcontext driContext; + + GLint bound_tex_object; +}; + + +/** subclass of _EGLSurface */ +struct xdri_egl_surface +{ + _EGLSurface Base; /**< base class */ + + __DRIid driDrawable; /**< DRI surface */ + drm_drawable_t hDrawable; +}; + + +/** subclass of _EGLConfig */ +struct xdri_egl_config +{ + _EGLConfig Base; /**< base class */ + + const __GLcontextModes *mode; /**< corresponding GLX mode */ +}; + + + +/** cast wrapper */ +static struct xdri_egl_driver * +xdri_egl_driver(_EGLDriver *drv) +{ + return (struct xdri_egl_driver *) drv; +} + + +/** Map EGLSurface handle to xdri_egl_surface object */ +static struct xdri_egl_surface * +lookup_surface(EGLSurface surf) +{ + _EGLSurface *surface = _eglLookupSurface(surf); + return (struct xdri_egl_surface *) surface; +} + + +/** Map EGLContext handle to xdri_egl_context object */ +static struct xdri_egl_context * +lookup_context(EGLContext c) +{ + _EGLContext *context = _eglLookupContext(c); + return (struct xdri_egl_context *) context; +} + +static struct xdri_egl_context * +current_context(void) +{ + return (struct xdri_egl_context *) _eglGetCurrentContext(); +} + +/** Map EGLConfig handle to xdri_egl_config object */ +static struct xdri_egl_config * +lookup_config(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config) +{ + _EGLConfig *conf = _eglLookupConfig(drv, dpy, config); + return (struct xdri_egl_config *) conf; +} + + + +/** Get size of given window */ +static Status +get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height) +{ + Window root; + Status stat; + int xpos, ypos; + unsigned int w, h, bw, depth; + stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); + *width = w; + *height = h; + return stat; +} + + +/** + * Produce a set of EGL configs. + * Note that we get the list of GLcontextModes from the GLX library. + * This dependency on GLX lib will be removed someday. + */ +static void +create_configs(_EGLDisplay *disp, __GLXdisplayPrivate *glx_priv) +{ + static const EGLint all_apis = (EGL_OPENGL_ES_BIT | + EGL_OPENGL_ES2_BIT | + EGL_OPENVG_BIT | + EGL_OPENGL_BIT); + __GLXscreenConfigs *scrn = glx_priv->screenConfigs; + const __GLcontextModes *m; + int id = 1; + + for (m = scrn->configs; m; m = m->next) { + /* EGL requires double-buffered configs */ + 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); + /* XXX only window rendering allowed ATM */ + SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE, + (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)); + + /* XXX possibly other things to init... */ + + /* Ptr from EGL config to GLcontextMode. Used in CreateContext(). */ + config->mode = m; + + _eglAddConfig(disp, &config->Base); + } + } +} + + +/** + * Called via __DRIinterfaceMethods object + */ +static __DRIfuncPtr +dri_get_proc_address(const char * proc_name) +{ + return NULL; +} + + +static void +dri_context_modes_destroy(__GLcontextModes *modes) +{ + _eglLog(_EGL_DEBUG, "%s", __FUNCTION__); + + while (modes) { + __GLcontextModes * const next = modes->next; + free(modes); + modes = next; + } +} + + +/** + * Create a linked list of 'count' GLcontextModes. + * These are used during the client/server visual negotiation phase, + * then discarded. + */ +static __GLcontextModes * +dri_context_modes_create(unsigned count, size_t minimum_size) +{ + /* This code copied from libGLX, and modified */ + const size_t size = (minimum_size > sizeof(__GLcontextModes)) + ? minimum_size : sizeof(__GLcontextModes); + __GLcontextModes * head = NULL; + __GLcontextModes ** next; + unsigned i; + + next = & head; + for (i = 0 ; i < count ; i++) { + *next = (__GLcontextModes *) calloc(1, size); + if (*next == NULL) { + dri_context_modes_destroy(head); + head = NULL; + break; + } + + (*next)->doubleBufferMode = 1; + (*next)->visualID = GLX_DONT_CARE; + (*next)->visualType = GLX_DONT_CARE; + (*next)->visualRating = GLX_NONE; + (*next)->transparentPixel = GLX_NONE; + (*next)->transparentRed = GLX_DONT_CARE; + (*next)->transparentGreen = GLX_DONT_CARE; + (*next)->transparentBlue = GLX_DONT_CARE; + (*next)->transparentAlpha = GLX_DONT_CARE; + (*next)->transparentIndex = GLX_DONT_CARE; + (*next)->xRenderable = GLX_DONT_CARE; + (*next)->fbconfigID = GLX_DONT_CARE; + (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; + (*next)->bindToTextureRgb = GLX_DONT_CARE; + (*next)->bindToTextureRgba = GLX_DONT_CARE; + (*next)->bindToMipmapTexture = GLX_DONT_CARE; + (*next)->bindToTextureTargets = 0; + (*next)->yInverted = GLX_DONT_CARE; + + next = & ((*next)->next); + } + + return head; +} + + +static __DRIscreen * +dri_find_dri_screen(__DRInativeDisplay *ndpy, int scrn) +{ + __GLXdisplayPrivate *priv = __glXInitialize(ndpy); + __GLXscreenConfigs *scrnConf = priv->screenConfigs; + return &scrnConf->driScreen; +} + + +static GLboolean +dri_window_exists(__DRInativeDisplay *ndpy, __DRIid draw) +{ + return EGL_TRUE; +} + + +static GLboolean +dri_create_context(__DRInativeDisplay *ndpy, int screenNum, int configID, + void * contextID, drm_context_t * hw_context) +{ + assert(configID >= 0); + return XF86DRICreateContextWithConfig(ndpy, screenNum, + configID, contextID, hw_context); +} + + +static GLboolean +dri_destroy_context(__DRInativeDisplay * ndpy, int screen, __DRIid context) +{ + return XF86DRIDestroyContext(ndpy, screen, context); +} + + +static GLboolean +dri_create_drawable(__DRInativeDisplay * ndpy, int screen, + __DRIid drawable, drm_drawable_t * hHWDrawable) +{ + _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__); + + /* Create DRI drawable for given window ID (drawable) */ + if (!XF86DRICreateDrawable(ndpy, screen, drawable, hHWDrawable)) + return EGL_FALSE; + + return EGL_TRUE; +} + + +static GLboolean +dri_destroy_drawable(__DRInativeDisplay * ndpy, int screen, __DRIid drawable) +{ + _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__); + return XF86DRIDestroyDrawable(ndpy, screen, drawable); +} + + +static GLboolean +dri_get_drawable_info(__DRInativeDisplay *ndpy, int scrn, + __DRIid draw, unsigned int * index, unsigned int * stamp, + int * x, int * y, int * width, int * height, + int * numClipRects, drm_clip_rect_t ** pClipRects, + int * backX, int * backY, + int * numBackClipRects, + drm_clip_rect_t ** pBackClipRects) +{ + _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__); + + if (!XF86DRIGetDrawableInfo(ndpy, scrn, draw, index, stamp, + x, y, width, height, + numClipRects, pClipRects, + backX, backY, + numBackClipRects, pBackClipRects)) { + return EGL_FALSE; + } + + return EGL_TRUE; +} + + +/** + * Table of functions exported by the loader to the driver. + */ +static const __DRIinterfaceMethods interface_methods = { + dri_get_proc_address, + + dri_context_modes_create, + dri_context_modes_destroy, + + dri_find_dri_screen, + dri_window_exists, + + dri_create_context, + dri_destroy_context, + + dri_create_drawable, + dri_destroy_drawable, + dri_get_drawable_info, + + NULL,/*__eglGetUST,*/ + NULL,/*__eglGetMSCRate,*/ +}; + + + +static EGLBoolean +init_drm(struct xdri_egl_driver *xdri_drv, _EGLDisplay *disp) +{ + __DRIversion ddx_version; + __DRIversion dri_version; + __DRIversion drm_version; + drmVersionPtr version; + drm_handle_t hFB; + int newlyopened; + int status; + int scrn = DefaultScreen(disp->Xdpy); + +#if 0 + createNewScreen = (PFNCREATENEWSCREENFUNC) + dlsym(xdri_drv->dri_driver_handle, createNewScreenName); + if (!createNewScreen) { + _eglLog(_EGL_WARNING, "XDRI: Couldn't find %s function in the driver.", + createNewScreenName); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: Found %s", createNewScreenName); + } +#endif + + /* + * Get the DRI X extension version. + */ + dri_version.major = 4; + dri_version.minor = 0; + dri_version.patch = 0; + + if (!XF86DRIOpenConnection(disp->Xdpy, scrn, + &xdri_drv->hSAREA, &xdri_drv->busID)) { + _eglLog(_EGL_WARNING, "XF86DRIOpenConnection failed"); + } + + xdri_drv->drmFD = drmOpenOnce(NULL, xdri_drv->busID, &newlyopened); + if (xdri_drv->drmFD < 0) { + perror("drmOpenOnce failed: "); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: drmOpenOnce returned %d", xdri_drv->drmFD); + } + + + if (drmGetMagic(xdri_drv->drmFD, &xdri_drv->magic)) { + perror("drmGetMagic failed: "); + return EGL_FALSE; + } + + version = drmGetVersion(xdri_drv->drmFD); + if (version) { + drm_version.major = version->version_major; + drm_version.minor = version->version_minor; + drm_version.patch = version->version_patchlevel; + drmFreeVersion(version); + _eglLog(_EGL_DEBUG, "XDRI: Got DRM version %d.%d.%d", + drm_version.major, + drm_version.minor, + drm_version.patch); + } + else { + drm_version.major = -1; + drm_version.minor = -1; + drm_version.patch = -1; + _eglLog(_EGL_WARNING, "XDRI: drmGetVersion() failed"); + return EGL_FALSE; + } + + /* Authenticate w/ server. + */ + if (!XF86DRIAuthConnection(disp->Xdpy, scrn, xdri_drv->magic)) { + _eglLog(_EGL_WARNING, "XDRI: XF86DRIAuthConnection() failed"); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: XF86DRIAuthConnection() success"); + } + + /* Get ddx version. + */ + { + char *driverName; + + /* + * Get device name (like "tdfx") and the ddx version + * numbers. We'll check the version in each DRI driver's + * "createNewScreen" function. + */ + if (!XF86DRIGetClientDriverName(disp->Xdpy, scrn, + &ddx_version.major, + &ddx_version.minor, + &ddx_version.patch, + &driverName)) { + _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetClientDriverName failed"); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetClientDriverName returned %s", driverName); + } + } + + /* Get framebuffer info. + */ + { + int junk; + if (!XF86DRIGetDeviceInfo(disp->Xdpy, scrn, + &hFB, + &junk, + &xdri_drv->framebuffer.size, + &xdri_drv->framebuffer.stride, + &xdri_drv->framebuffer.dev_priv_size, + &xdri_drv->framebuffer.dev_priv)) { + _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetDeviceInfo() failed"); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetDeviceInfo() success"); + } + xdri_drv->framebuffer.width = DisplayWidth(disp->Xdpy, scrn); + xdri_drv->framebuffer.height = DisplayHeight(disp->Xdpy, scrn); + } + + /* Map the framebuffer region. (this may not be needed) + */ + status = drmMap(xdri_drv->drmFD, hFB, xdri_drv->framebuffer.size, + (drmAddressPtr) &xdri_drv->framebuffer.base); + if (status != 0) { + _eglLog(_EGL_WARNING, "XDRI: drmMap(framebuffer) failed"); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: drmMap(framebuffer) success"); + } + + /* Map the SAREA region. + */ + status = drmMap(xdri_drv->drmFD, xdri_drv->hSAREA, SAREA_MAX, &xdri_drv->pSAREA); + if (status != 0) { + _eglLog(_EGL_WARNING, "XDRI: drmMap(sarea) failed"); + return EGL_FALSE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: drmMap(sarea) success"); + } + + return EGL_TRUE; +} + + +/** + * Load the DRI driver named by "xdri_drv->dri_driver_name". + * Basically, dlopen() the library to set "xdri_drv->dri_driver_handle". + * + * Later, we'll call dlsym(createNewScreenName) to get a pointer to + * the driver's createNewScreen() function which is the bootstrap function. + * + * \return EGL_TRUE for success, EGL_FALSE for failure + */ +static EGLBoolean +load_dri_driver(struct xdri_egl_driver *xdri_drv) +{ + char filename[100]; + int flags = RTLD_NOW; + + /* try "egl_xxx_dri.so" first */ + snprintf(filename, sizeof(filename), "egl_%s.so", xdri_drv->dri_driver_name); + _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename); + xdri_drv->dri_driver_handle = dlopen(filename, flags); + if (xdri_drv->dri_driver_handle) { + _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename); + return EGL_TRUE; + } + else { + _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) fail (%s)", filename, dlerror()); + } + + /* try regular "xxx_dri.so" next */ + snprintf(filename, sizeof(filename), "%s.so", xdri_drv->dri_driver_name); + _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename); + xdri_drv->dri_driver_handle = dlopen(filename, flags); + if (xdri_drv->dri_driver_handle) { + _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s) OK", filename); + return EGL_TRUE; + } + + _eglLog(_EGL_WARNING, "XDRI Could not open %s (%s)", filename, dlerror()); + return EGL_FALSE; +} + + +/** + * Called via eglInitialize(), xdri_drv->API.Initialize(). + */ +static EGLBoolean +xdri_eglInitialize(_EGLDriver *drv, EGLDisplay dpy, + EGLint *minor, EGLint *major) +{ + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + _EGLDisplay *disp = _eglLookupDisplay(dpy); + static char name[100]; + + _eglLog(_EGL_DEBUG, "XDRI: eglInitialize"); + + if (!disp->Xdpy) { + disp->Xdpy = XOpenDisplay(NULL); + if (!disp->Xdpy) { + _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed"); + return EGL_FALSE; + } + } + +#if 0 + /* choose the DRI driver to load */ + xdri_drv->dri_driver_name = _eglChooseDRMDriver(0); + if (!load_dri_driver(xdri_drv)) + return EGL_FALSE; +#else + (void) load_dri_driver; +#endif + +#if 0 + if (!init_drm(xdri_drv, disp)) + return EGL_FALSE; +#else + (void) init_drm; +#endif + + /* + * NOTE: this call to __glXInitialize() bootstraps the whole GLX/DRI + * interface, loads the DRI driver, etc. + * This replaces the load_dri_driver() and init_drm() code above. + */ + xdri_drv->glx_priv = __glXInitialize(disp->Xdpy); + + create_configs(disp, xdri_drv->glx_priv); + + xdri_drv->Base.Initialized = EGL_TRUE; + + if (xdri_drv->dri_driver_name) + snprintf(name, sizeof(name), "X/DRI:%s", xdri_drv->dri_driver_name); + else + snprintf(name, sizeof(name), "X/DRI"); + xdri_drv->Base.Name = name; + + /* we're supporting EGL 1.4 */ + *minor = 1; + *major = 4; + + return EGL_TRUE; +} + + +/* + * Do some clean-up that normally occurs in XCloseDisplay(). + * We do this here because we're about to unload a dynamic library + * that has added some per-display extension data and callbacks. + * If we don't do this here we'll crash in XCloseDisplay() because it'll + * try to call functions that went away when the driver library was unloaded. + */ +static void +FreeDisplayExt(Display *dpy) +{ + _XExtension *ext, *next; + + for (ext = dpy->ext_procs; ext; ext = next) { + next = ext->next; + if (ext->close_display) { + ext->close_display(dpy, &ext->codes); + ext->close_display = NULL; + } + if (ext->name) + Xfree(ext->name); + Xfree(ext); + } + dpy->ext_procs = NULL; + + _XFreeExtData (dpy->ext_data); + dpy->ext_data = NULL; +} + + +/** + * Called via eglTerminate(), drv->API.Terminate(). + */ +static EGLBoolean +xdri_eglTerminate(_EGLDriver *drv, EGLDisplay dpy) +{ + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + _eglLog(_EGL_DEBUG, "XDRI: eglTerminate"); + + _eglLog(_EGL_DEBUG, "XDRI: Closing %s", xdri_drv->dri_driver_name); + + FreeDisplayExt(disp->Xdpy); + +#if 0 + /* this causes a segfault for some reason */ + dlclose(xdri_drv->dri_driver_handle); +#endif + xdri_drv->dri_driver_handle = NULL; + + free((void*) xdri_drv->dri_driver_name); + + return EGL_TRUE; +} + + +/* + * Called from eglGetProcAddress() via drv->API.GetProcAddress(). + */ +static _EGLProc +xdri_eglGetProcAddress(const char *procname) +{ +#if 0 + _EGLDriver *drv = NULL; + + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + /*_EGLDisplay *disp = _eglLookupDisplay(dpy);*/ + _EGLProc *proc = xdri_drv->driScreen.getProcAddress(procname); + return proc; +#elif 1 + /* 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 (*st_get_proc_addr)(const char *procname); + st_get_proc_addr = dlsym(NULL, "st_get_proc_address"); + if (st_get_proc_addr) { + return st_get_proc_addr(procname); + } + return NULL; +#else + return NULL; +#endif +} + + +/** + * Called via eglCreateContext(), drv->API.CreateContext(). + */ +static EGLContext +xdri_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config); + void *shared = NULL; + int renderType = GLX_RGBA_BIT; + + struct xdri_egl_context *xdri_ctx = CALLOC_STRUCT(xdri_egl_context); + if (!xdri_ctx) + return EGL_NO_CONTEXT; + + if (!_eglInitContext(drv, dpy, &xdri_ctx->Base, config, attrib_list)) { + free(xdri_ctx); + return EGL_NO_CONTEXT; + } + + assert(xdri_config); + + { + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs; + xdri_ctx->driContext.private = + scrnConf->driScreen.createNewContext(disp->Xdpy, + xdri_config->mode, renderType, + shared, &xdri_ctx->driContext); + } + + if (!xdri_ctx->driContext.private) { + _eglLog(_EGL_DEBUG, "driScreen.createNewContext failed"); + free(xdri_ctx); + return EGL_NO_CONTEXT; + } + + xdri_ctx->driContext.mode = xdri_config->mode; + + return _eglGetContextHandle(&xdri_ctx->Base); +} + + +/** + * Called via eglMakeCurrent(), drv->API.MakeCurrent(). + */ +static EGLBoolean +xdri_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, + EGLSurface r, EGLContext context) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct xdri_egl_context *xdri_ctx = lookup_context(context); + struct xdri_egl_surface *xdri_draw = lookup_surface(d); + struct xdri_egl_surface *xdri_read = lookup_surface(r); + __DRIid draw = xdri_draw ? xdri_draw->driDrawable : 0; + __DRIid read = xdri_read ? xdri_read->driDrawable : 0; + int scrn = DefaultScreen(disp->Xdpy); + + if (!_eglMakeCurrent(drv, dpy, d, r, context)) + return EGL_FALSE; + + + if (xdri_ctx && + !xdri_ctx->driContext.bindContext(disp->Xdpy, scrn, draw, read, + &xdri_ctx->driContext)) { + return EGL_FALSE; + } + + return EGL_TRUE; +} + + +/** + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). + */ +static EGLSurface +xdri_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + NativeWindowType window, const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct xdri_egl_surface *xdri_surf; + int scrn = DefaultScreen(disp->Xdpy); + uint width, height; + + xdri_surf = CALLOC_STRUCT(xdri_egl_surface); + if (!xdri_surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_WINDOW_BIT, + config, attrib_list)) { + free(xdri_surf); + return EGL_FALSE; + } + + if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) { + free(xdri_surf); + return EGL_FALSE; + } + + xdri_surf->driDrawable = window; + + _eglSaveSurface(&xdri_surf->Base); + + get_drawable_size(disp->Xdpy, window, &width, &height); + xdri_surf->Base.Width = width; + xdri_surf->Base.Height = height; + + _eglLog(_EGL_DEBUG, + "XDRI: CreateWindowSurface win 0x%x handle %d hDrawable %d", + (int) window, _eglGetSurfaceHandle(&xdri_surf->Base), + (int) xdri_surf->hDrawable); + + return _eglGetSurfaceHandle(&xdri_surf->Base); +} + + +/** + * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface(). + */ +static EGLSurface +xdri_eglCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + struct xdri_egl_surface *xdri_surf; + struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config); + int scrn = DefaultScreen(disp->Xdpy); + Window window; + + xdri_surf = CALLOC_STRUCT(xdri_egl_surface); + if (!xdri_surf) + return EGL_NO_SURFACE; + + if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_PBUFFER_BIT, + config, attrib_list)) { + free(xdri_surf); + return EGL_FALSE; + } + + /* Create a dummy X window */ + { + Window root = RootWindow(disp->Xdpy, scrn); + XSetWindowAttributes attr; + XVisualInfo *visInfo, visTemplate; + unsigned mask; + int nvis; + + visTemplate.visualid = xdri_config->mode->visualID; + visInfo = XGetVisualInfo(disp->Xdpy, VisualIDMask, &visTemplate, &nvis); + if (!visInfo) { + return EGL_NO_SURFACE; + } + + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(disp->Xdpy, root, + visInfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + window = XCreateWindow(disp->Xdpy, root, 0, 0, + xdri_surf->Base.Width, xdri_surf->Base.Height, + 0, visInfo->depth, InputOutput, + visInfo->visual, mask, &attr); + + /*XMapWindow(disp->Xdpy, window);*/ + XFree(visInfo); + + /* set hints and properties */ + /* + sizehints.width = xdri_surf->Base.Width; + sizehints.height = xdri_surf->Base.Height; + sizehints.flags = USPosition; + XSetNormalHints(disp->Xdpy, window, &sizehints); + */ + } + + if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) { + free(xdri_surf); + return EGL_FALSE; + } + + xdri_surf->driDrawable = window; + + _eglSaveSurface(&xdri_surf->Base); + + _eglLog(_EGL_DEBUG, + "XDRI: CreatePbufferSurface handle %d hDrawable %d", + _eglGetSurfaceHandle(&xdri_surf->Base), + (int) xdri_surf->hDrawable); + + return _eglGetSurfaceHandle(&xdri_surf->Base); +} + + + +static EGLBoolean +xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) +{ + struct xdri_egl_surface *xdri_surf = lookup_surface(surface); + if (xdri_surf) { + _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface); + if (xdri_surf->Base.IsBound) { + xdri_surf->Base.DeletePending = EGL_TRUE; + } + else { + /* + st_unreference_framebuffer(surf->Framebuffer); + */ + free(xdri_surf); + } + return EGL_TRUE; + } + else { + _eglError(EGL_BAD_SURFACE, "eglDestroySurface"); + return EGL_FALSE; + } +} + + +static EGLBoolean +xdri_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, + EGLint buffer) +{ + typedef int (*bind_teximage)(__DRInativeDisplay *dpy, + __DRIid surface, __DRIscreen *psc, + int buffer, int target, int format, + int level, int mipmap); + + bind_teximage egl_dri_bind_teximage; + + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + struct xdri_egl_context *xdri_ctx = current_context(); + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + struct xdri_egl_surface *xdri_surf = lookup_surface(surface); + + __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0; + + __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs; + __DRIscreen *psc = &scrnConf->driScreen; + + /* this call just does error checking */ + if (!_eglBindTexImage(drv, dpy, surface, buffer)) { + return EGL_FALSE; + } + + egl_dri_bind_teximage = + (bind_teximage) dlsym(NULL, "egl_dri_bind_teximage"); + if (egl_dri_bind_teximage) { + return egl_dri_bind_teximage(disp->Xdpy, dri_surf, psc, + buffer, + xdri_surf->Base.TextureTarget, + xdri_surf->Base.TextureFormat, + xdri_surf->Base.MipmapLevel, + xdri_surf->Base.MipmapTexture); + } + else { + /* fallback path based on glCopyTexImage() */ + /* Get/save currently bound 2D texobj name */ + glGetIntegerv_t glGetIntegerv_func = + (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv"); + GLint curTexObj = 0; + if (glGetIntegerv_func) { + (*glGetIntegerv_func)(GL_TEXTURE_BINDING_2D, &curTexObj); + } + xdri_ctx->bound_tex_object = curTexObj; + } + + return EGL_FALSE; +} + + +static EGLBoolean +xdri_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, + EGLint buffer) +{ + typedef int (*release_teximage)(__DRInativeDisplay *dpy, + __DRIid surface, __DRIscreen *psc, + int buffer, int target, int format, + int level, int mipmap); + release_teximage egl_dri_release_teximage; + + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + struct xdri_egl_context *xdri_ctx = current_context(); + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + struct xdri_egl_surface *xdri_surf = lookup_surface(surface); + + __DRIid dri_surf = xdri_surf ? xdri_surf->driDrawable : 0; + + __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs; + __DRIscreen *psc = &scrnConf->driScreen; + + /* this call just does error checking */ + if (!_eglReleaseTexImage(drv, dpy, surface, buffer)) { + return EGL_FALSE; + } + + egl_dri_release_teximage = + (release_teximage) dlsym(NULL, "egl_dri_release_teximage"); + if (egl_dri_release_teximage) { + return egl_dri_release_teximage(disp->Xdpy, dri_surf, psc, + buffer, + xdri_surf->Base.TextureTarget, + xdri_surf->Base.TextureFormat, + xdri_surf->Base.MipmapLevel, + xdri_surf->Base.MipmapTexture); + } + else { + /* fallback path based on glCopyTexImage() */ + glGetIntegerv_t glGetIntegerv_func = + (glGetIntegerv_t) dlsym(NULL, "glGetIntegerv"); + glBindTexture_t glBindTexture_func = + (glBindTexture_t) dlsym(NULL, "glBindTexture"); + glCopyTexImage2D_t glCopyTexImage2D_func = + (glCopyTexImage2D_t) dlsym(NULL, "glCopyTexImage2D"); + GLint curTexObj; + GLenum intFormat; + GLint level, width, height; + + if (xdri_surf->Base.TextureFormat == EGL_TEXTURE_RGBA) + intFormat = GL_RGBA; + else + intFormat = GL_RGB; + level = xdri_surf->Base.MipmapLevel; + width = xdri_surf->Base.Width >> level; + height = xdri_surf->Base.Height >> level; + + if (width > 0 && height > 0 && + glGetIntegerv_func && glBindTexture_func && glCopyTexImage2D_func) { + glGetIntegerv_func(GL_TEXTURE_BINDING_2D, &curTexObj); + /* restore texobj from time of eglBindTexImage() call */ + if (curTexObj != xdri_ctx->bound_tex_object) + glBindTexture_func(GL_TEXTURE_2D, xdri_ctx->bound_tex_object); + /* copy pbuffer image to texture */ + glCopyTexImage2D_func(GL_TEXTURE_2D, + level, + intFormat, + 0, 0, width, height, 0); + /* restore current texture */ + if (curTexObj != xdri_ctx->bound_tex_object) + glBindTexture_func(GL_TEXTURE_2D, curTexObj); + } + xdri_ctx->bound_tex_object = -1; + } + + return EGL_FALSE; +} + + +static EGLBoolean +xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) +{ + _EGLDisplay *disp = _eglLookupDisplay(dpy); + + _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers"); + + /* error checking step: */ + if (!_eglSwapBuffers(drv, dpy, draw)) + return EGL_FALSE; + + { + struct xdri_egl_surface *xdri_surf = lookup_surface(draw); + struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv); + __GLXscreenConfigs *scrnConf = xdri_drv->glx_priv->screenConfigs; + __DRIscreen *psc = &scrnConf->driScreen; + __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy, + xdri_surf->driDrawable, + psc->private); + + if (pdraw) + pdraw->swapBuffers(disp->Xdpy, pdraw->private); + else + _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers"); + } + + return EGL_TRUE; +} + + +/** + * This is the main entrypoint into the driver, called by libEGL. + * Create a new _EGLDriver object and init its dispatch table. + */ +_EGLDriver * +_eglMain(_EGLDisplay *disp, const char *args) +{ + struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver); + if (!xdri_drv) + return NULL; + + /* Tell libGL to prefer the EGL drivers over regular DRI drivers */ + __glXPreferEGL(1); + + _eglInitDriverFallbacks(&xdri_drv->Base); + xdri_drv->Base.API.Initialize = xdri_eglInitialize; + xdri_drv->Base.API.Terminate = xdri_eglTerminate; + + xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress; + + xdri_drv->Base.API.CreateContext = xdri_eglCreateContext; + xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent; + xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface; + xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface; + xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface; + xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage; + xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage; + xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers; + + xdri_drv->Base.ClientAPIsMask = (EGL_OPENGL_BIT | + EGL_OPENGL_ES_BIT | + EGL_OPENGL_ES2_BIT | + EGL_OPENVG_BIT); + xdri_drv->Base.Name = "X/DRI"; + + _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args); + + return &xdri_drv->Base; +} diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile index 7ab78197c7..8ea60c0199 100644 --- a/src/egl/main/Makefile +++ b/src/egl/main/Makefile @@ -8,34 +8,49 @@ INCLUDE_DIRS = -I$(TOP)/include -I$(TOP)/src/mesa/glapi HEADERS = \ eglconfig.h \ + eglconfigutil.h \ eglcontext.h \ + egldefines.h \ egldisplay.h \ egldriver.h \ eglglobals.h \ egllog.h \ eglhash.h \ + eglmisc.h \ eglmode.h \ eglscreen.h \ - eglsurface.h + eglstring.h \ + eglsurface.h \ + eglx.h SOURCES = \ eglapi.c \ eglconfig.c \ + eglconfigutil.c \ eglcontext.c \ egldisplay.c \ egldriver.c \ eglglobals.c \ egllog.c \ eglhash.c \ + eglmisc.c \ eglmode.c \ eglscreen.c \ - eglsurface.c + eglstring.c \ + eglsurface.c \ + eglx.c OBJECTS = $(SOURCES:.c=.o) +# Undefined for now +LOCAL_CFLAGS = -D_EGL_PLATFORM_X=1 + +LIBS = -lX11 + + .c.o: - $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(LOCAL_CFLAGS) $< -o $@ @@ -48,7 +63,7 @@ library: $(TOP)/$(LIB_DIR)/libEGL.so $(TOP)/$(LIB_DIR)/libEGL.so: $(OBJECTS) $(MKLIB) -o EGL -linker '$(CC)' -ldflags '$(LDFLAGS)' \ -major 1 -minor 0 \ - -install $(TOP)/$(LIB_DIR) -ldl $(OBJECTS) + -install $(TOP)/$(LIB_DIR) -ldl $(OBJECTS) $(LIBS) @@ -59,9 +74,11 @@ clean: depend: $(SOURCES) $(HEADERS) @ echo "running $(MKDEP)" + @ rm -f depend @ touch depend $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \ - $(SOURCES) $(HEADERS) > /dev/null + $(SOURCES) $(HEADERS) > /dev/null 2>/dev/null + include depend # DO NOT DELETE diff --git a/src/egl/main/README.txt b/src/egl/main/README.txt new file mode 100644 index 0000000000..b3d253dd13 --- /dev/null +++ b/src/egl/main/README.txt @@ -0,0 +1,71 @@ + + +Notes about the EGL library: + + +The EGL code here basically consists of two things: + +1. An EGL API dispatcher. This directly routes all the eglFooBar() API + calls into driver-specific functions. + +2. Fallbacks for EGL API functions. A driver _could_ implement all the + EGL API calls from scratch. But in many cases, the fallbacks provided + in libEGL (such as eglChooseConfig()) will do the job. + + + +Bootstrapping: + +When the apps calls eglOpenDisplay() a device driver is selected and loaded +(look for dlsym() or LoadLibrary() in egldriver.c). + +The driver's _eglMain() function is then called. This driver function +allocates, initializes and returns a new _EGLDriver object (usually a +subclass of that type). + +As part of initialization, the dispatch table in _EGLDriver->API must be +populated with all the EGL entrypoints. Typically, _eglInitDriverFallbacks() +can be used to plug in default/fallback functions. Some functions like +driver->API.Initialize and driver->API.Terminate _must_ be implemented +with driver-specific code (no default/fallback function is possible). + + +A bit later, the app will call eglInitialize(). This will get routed +to the driver->API.Initialize() function. Any additional driver +initialization that wasn't done in _eglMain() should be done at this +point. Typically, this will involve setting up visual configs, etc. + + + +Special Functions: + +Certain EGL functions _must_ be implemented by the driver. This includes: + +eglCreateContext +eglCreateWindowSurface +eglCreatePixmapSurface +eglCreatePBufferSurface +eglMakeCurrent +eglSwapBuffers + +Most of the EGLConfig-related functions can be implemented with the +defaults/fallbacks. Same thing for the eglGet/Query functions. + + + + +Teardown: + +When eglTerminate() is called, the driver->API.Terminate() function is +called. The driver should clean up after itself. eglTerminate() will +then close/unload the driver (shared library). + + + + +Subclassing: + +The internal libEGL data structures such as _EGLDisplay, _EGLContext, +_EGLSurface, etc should be considered base classes from which drivers +will derive subclasses. + diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index bfa580e6c3..9df938e188 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -43,36 +43,63 @@ /** - * NOTE: displayName is treated as a string in _eglChooseDriver()!!! - * This will probably change! - * See _eglChooseDriver() for details! + * This is typically the first EGL function that an application calls. + * We initialize our global vars and create a private _EGLDisplay object. */ -EGLDisplay APIENTRY -eglGetDisplay(NativeDisplayType displayName) +EGLDisplay EGLAPIENTRY +eglGetDisplay(NativeDisplayType nativeDisplay) { _EGLDisplay *dpy; _eglInitGlobals(); - dpy = _eglNewDisplay(displayName); - if (dpy) - return dpy->Handle; - else - return EGL_NO_DISPLAY; + dpy = _eglNewDisplay(nativeDisplay); + return _eglGetDisplayHandle(dpy); } -EGLBoolean APIENTRY +/** + * This is typically the second EGL function that an application calls. + * Here we load/initialize the actual hardware driver. + */ +EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { + EGLint major_int, minor_int; + if (dpy) { - _EGLDriver *drv = _eglChooseDriver(dpy); - if (drv) - return drv->API.Initialize(drv, dpy, major, minor); + EGLBoolean retVal; + _EGLDisplay *dpyPriv = _eglLookupDisplay(dpy); + if (!dpyPriv) { + return EGL_FALSE; + } + dpyPriv->Driver = _eglOpenDriver(dpyPriv, + dpyPriv->DriverName, + dpyPriv->DriverArgs); + if (!dpyPriv->Driver) { + return EGL_FALSE; + } + /* Initialize the particular driver now */ + retVal = dpyPriv->Driver->API.Initialize(dpyPriv->Driver, dpy, + &major_int, &minor_int); + + dpyPriv->Driver->APImajor = major_int; + dpyPriv->Driver->APIminor = minor_int; + snprintf(dpyPriv->Driver->Version, sizeof(dpyPriv->Driver->Version), + "%d.%d (%s)", major_int, minor_int, dpyPriv->Driver->Name); + + /* Update applications version of major and minor if not NULL */ + if((major != NULL) && (minor != NULL)) + { + *major = major_int; + *minor = minor_int; + } + + return retVal; } return EGL_FALSE; } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -83,7 +110,7 @@ eglTerminate(EGLDisplay dpy) } -const char * APIENTRY +const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -94,7 +121,7 @@ eglQueryString(EGLDisplay dpy, EGLint name) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -103,7 +130,7 @@ eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *nu } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -111,7 +138,7 @@ eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, E } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -119,7 +146,7 @@ eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *v } -EGLContext APIENTRY +EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -127,7 +154,7 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, const } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -135,7 +162,7 @@ eglDestroyContext(EGLDisplay dpy, EGLContext ctx) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -143,7 +170,7 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -151,7 +178,7 @@ eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) } -EGLSurface APIENTRY +EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -159,7 +186,7 @@ eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window } -EGLSurface APIENTRY +EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -167,7 +194,7 @@ eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap } -EGLSurface APIENTRY +EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -175,7 +202,7 @@ eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_l } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -183,7 +210,7 @@ eglDestroySurface(EGLDisplay dpy, EGLSurface surface) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -191,7 +218,7 @@ eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *va } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -199,7 +226,7 @@ eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint va } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -207,7 +234,7 @@ eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -215,7 +242,7 @@ eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -223,7 +250,7 @@ eglSwapInterval(EGLDisplay dpy, EGLint interval) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -231,7 +258,7 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -239,7 +266,7 @@ eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglWaitGL(void) { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -252,7 +279,7 @@ eglWaitGL(void) } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -265,40 +292,31 @@ eglWaitNative(EGLint engine) } -EGLDisplay APIENTRY +EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) { _EGLDisplay *dpy = _eglGetCurrentDisplay(); - if (dpy) - return dpy->Handle; - else - return EGL_NO_DISPLAY; + return _eglGetDisplayHandle(dpy); } -EGLContext APIENTRY +EGLContext EGLAPIENTRY eglGetCurrentContext(void) { _EGLContext *ctx = _eglGetCurrentContext(); - if (ctx) - return ctx->Handle; - else - return EGL_NO_CONTEXT; + return _eglGetContextHandle(ctx); } -EGLSurface APIENTRY +EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) { _EGLSurface *s = _eglGetCurrentSurface(readdraw); - if (s) - return s->Handle; - else - return EGL_NO_SURFACE; + return _eglGetSurfaceHandle(s); } -EGLint APIENTRY +EGLint EGLAPIENTRY eglGetError(void) { _EGLThreadInfo *t = _eglGetCurrentThread(); @@ -308,7 +326,7 @@ eglGetError(void) } -void (* APIENTRY eglGetProcAddress(const char *procname))() +void (* EGLAPIENTRY eglGetProcAddress(const char *procname))() { typedef void (*genericFunc)(); struct name_function { @@ -376,12 +394,15 @@ void (* APIENTRY eglGetProcAddress(const char *procname))() return (genericFunc) egl_functions[i].function; } } -#if 0 - /* XXX enable this code someday */ - return (genericFunc) _glapi_get_proc_address(procname); -#else + + /* now loop over drivers to query their procs */ + for (i = 0; i < _eglGlobal.NumDrivers; i++) { + _EGLProc p = _eglGlobal.Drivers[i]->API.GetProcAddress(procname); + if (p) + return p; + } + return NULL; -#endif } @@ -389,7 +410,7 @@ void (* APIENTRY eglGetProcAddress(const char *procname))() * EGL_MESA_screen extension */ -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglChooseModeMESA(EGLDisplay dpy, EGLScreenMESA screen, const EGLint *attrib_list, EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes) @@ -402,7 +423,7 @@ eglChooseModeMESA(EGLDisplay dpy, EGLScreenMESA screen, } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglGetModesMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *modes, EGLint mode_size, EGLint *num_mode) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -413,7 +434,7 @@ eglGetModesMESA(EGLDisplay dpy, EGLScreenMESA screen, EGLModeMESA *modes, EGLint } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglGetModeAttribMESA(EGLDisplay dpy, EGLModeMESA mode, EGLint attribute, EGLint *value) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -424,7 +445,7 @@ eglGetModeAttribMESA(EGLDisplay dpy, EGLModeMESA mode, EGLint attribute, EGLint } -EGLBoolean APIENTRY +EGLBoolean EGLAPIENTRY eglCopyContextMESA(EGLDisplay dpy, EGLContext source, EGLContext dest, EGLint mask) { _EGLDriver *drv = _eglLookupDriver(dpy); @@ -508,21 +529,42 @@ eglQueryModeStringMESA(EGLDisplay dpy, EGLModeMESA mode) #ifdef EGL_VERSION_1_2 + +/** + * Specify the client API to use for subsequent calls including: + * eglCreateContext() + * eglGetCurrentContext() + * eglGetCurrentDisplay() + * eglGetCurrentSurface() + * eglMakeCurrent(when the ctx parameter is EGL NO CONTEXT) + * eglWaitClient() + * eglWaitNative() + * See section 3.7 "Rendering Context" in the EGL specification for details. + */ EGLBoolean eglBindAPI(EGLenum api) { _EGLThreadInfo *t = _eglGetCurrentThread(); switch (api) { +#ifdef EGL_VERSION_1_4 + case EGL_OPENGL_API: + if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_BIT) { + t->CurrentAPI = api; + return EGL_TRUE; + } + _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); + return EGL_FALSE; +#endif case EGL_OPENGL_ES_API: - if (_eglGlobal.OpenGLESAPISupported) { + if (_eglGlobal.ClientAPIsMask & (EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)) { t->CurrentAPI = api; return EGL_TRUE; } _eglError(EGL_BAD_PARAMETER, "eglBindAPI"); return EGL_FALSE; case EGL_OPENVG_API: - if (_eglGlobal.OpenVGAPISupported) { + if (_eglGlobal.ClientAPIsMask & EGL_OPENVG_BIT) { t->CurrentAPI = api; return EGL_TRUE; } @@ -535,6 +577,18 @@ eglBindAPI(EGLenum api) } +/** + * Return the last value set with eglBindAPI(). + */ +EGLenum +eglQueryAPI(void) +{ + /* returns one of EGL_OPENGL_API, EGL_OPENGL_ES_API or EGL_OPENVG_API */ + _EGLThreadInfo *t = _eglGetCurrentThread(); + return t->CurrentAPI; +} + + EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, @@ -546,15 +600,6 @@ eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, } -EGLenum -eglQueryAPI(void) -{ - /* returns one of EGL_OPENGL_ES_API or EGL_OPENVG_API */ - _EGLThreadInfo *t = _eglGetCurrentThread(); - return t->CurrentAPI; -} - - EGLBoolean eglReleaseThread(void) { diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index 555aa5dd9e..f6163a0c7a 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -2,10 +2,15 @@ #define EGLAPI_INCLUDED /** - * Typedefs for all EGL API entrypoint functions. + * A generic function ptr type */ +typedef void (*_EGLProc)(); +/** + * Typedefs for all EGL API entrypoint functions. + */ + /* driver funcs */ typedef EGLBoolean (*Initialize_t)(_EGLDriver *, EGLDisplay dpy, EGLint *major, EGLint *minor); typedef EGLBoolean (*Terminate_t)(_EGLDriver *, EGLDisplay dpy); @@ -39,6 +44,9 @@ typedef const char *(*QueryString_t)(_EGLDriver *drv, EGLDisplay dpy, EGLint nam typedef EGLBoolean (*WaitGL_t)(_EGLDriver *drv, EGLDisplay dpy); typedef EGLBoolean (*WaitNative_t)(_EGLDriver *drv, EGLDisplay dpy, EGLint engine); +typedef _EGLProc (*GetProcAddress_t)(const char *procname); + + #ifdef EGL_MESA_screen_surface typedef EGLBoolean (*ChooseModeMESA_t)(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, const EGLint *attrib_list, EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes); @@ -95,6 +103,7 @@ struct _egl_api QueryString_t QueryString; WaitGL_t WaitGL; WaitNative_t WaitNative; + GetProcAddress_t GetProcAddress; /* EGL_MESA_screen extension */ ChooseModeMESA_t ChooseModeMESA; diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index 2a62f95b54..b19988f49a 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -17,48 +17,6 @@ #define MIN2(A, B) (((A) < (B)) ? (A) : (B)) -/** - * Convert an _EGLConfig to a __GLcontextModes object. - * NOTE: This routine may be incomplete - we're only making sure that - * the fields needed by Mesa (for _mesa_create_context/framebuffer) are - * set correctly. - */ -void -_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode) -{ - memset(mode, 0, sizeof(*mode)); - - mode->rgbMode = GL_TRUE; /* no color index */ - mode->colorIndexMode = GL_FALSE; - mode->doubleBufferMode = GL_TRUE; /* always DB for now */ - mode->stereoMode = GL_FALSE; - - mode->redBits = GET_CONFIG_ATTRIB(config, EGL_RED_SIZE); - mode->greenBits = GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE); - mode->blueBits = GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE); - mode->alphaBits = GET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE); - mode->rgbBits = GET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE); - - /* no rgba masks - fix? */ - - mode->depthBits = GET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE); - mode->haveDepthBuffer = mode->depthBits > 0; - - mode->stencilBits = GET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE); - mode->haveStencilBuffer = mode->stencilBits > 0; - - /* no accum */ - - mode->level = GET_CONFIG_ATTRIB(config, EGL_LEVEL); - mode->samples = GET_CONFIG_ATTRIB(config, EGL_SAMPLES); - mode->sampleBuffers = GET_CONFIG_ATTRIB(config, EGL_SAMPLE_BUFFERS); - - /* surface type - not really needed */ - mode->visualType = GLX_TRUE_COLOR; - mode->renderType = GLX_RGBA_BIT; -} - - void _eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val) { @@ -76,7 +34,7 @@ void _eglInitConfig(_EGLConfig *config, EGLint id) { memset(config, 0, sizeof(*config)); - config->Handle = id; + config->Handle = (EGLConfig) 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); @@ -85,9 +43,7 @@ _eglInitConfig(_EGLConfig *config, EGLint id) _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_SCREEN_BIT_MESA | EGL_PBUFFER_BIT | - EGL_PIXMAP_BIT | EGL_WINDOW_BIT); + _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); @@ -100,7 +56,19 @@ _eglInitConfig(_EGLConfig *config, EGLint id) /** + * Return the public handle for an internal _EGLConfig. + * This is the inverse of _eglLookupConfig(). + */ +EGLConfig +_eglGetConfigHandle(_EGLConfig *config) +{ + return config ? config->Handle : 0; +} + + +/** * Given an EGLConfig handle, return the corresponding _EGLConfig object. + * This is the inverse of _eglGetConfigHandle(). */ _EGLConfig * _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config) @@ -108,8 +76,8 @@ _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config) EGLint i; _EGLDisplay *disp = _eglLookupDisplay(dpy); for (i = 0; i < disp->NumConfigs; i++) { - if (disp->Configs[i].Handle == config) { - return disp->Configs + i; + if (disp->Configs[i]->Handle == config) { + return disp->Configs[i]; } } return NULL; @@ -118,23 +86,32 @@ _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config) /** * 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, const _EGLConfig *config) +_eglAddConfig(_EGLDisplay *display, _EGLConfig *config) { - _EGLConfig *newConfigs; + _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; - newConfigs = (_EGLConfig *) realloc(display->Configs, - (n + 1) * sizeof(_EGLConfig)); + /* realloc array of ptrs */ + newConfigs = (_EGLConfig **) realloc(display->Configs, + (n + 1) * sizeof(_EGLConfig *)); if (newConfigs) { display->Configs = newConfigs; - display->Configs[n] = *config; /* copy struct */ - display->Configs[n].Handle = n; + display->Configs[n] = config; display->NumConfigs++; - return display->Configs + n; + return config; } else { return NULL; @@ -176,7 +153,7 @@ _eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list) } else if (attr == EGL_RENDERABLE_TYPE) { EGLint renType = attrib_list[++i]; - if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT)) { + if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENVG_BIT)) { _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); return EGL_FALSE; } @@ -360,8 +337,8 @@ _eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, /* make array of pointers to qualifying configs */ for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) { - if (_eglConfigQualifies(disp->Configs + i, &criteria)) { - configList[count++] = disp->Configs + i; + if (_eglConfigQualifies(disp->Configs[i], &criteria)) { + configList[count++] = disp->Configs[i]; } } @@ -369,8 +346,10 @@ _eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs); /* copy config handles to output array */ - for (i = 0; i < count; i++) { - configs[i] = configList[i]->Handle; + if (configs) { + for (i = 0; i < count; i++) { + configs[i] = configList[i]->Handle; + } } free(configList); @@ -419,7 +398,7 @@ _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, EGLint i; *num_config = MIN2(disp->NumConfigs, config_size); for (i = 0; i < *num_config; i++) { - configs[i] = disp->Configs[i].Handle; + configs[i] = disp->Configs[i]->Handle; } } else { @@ -429,210 +408,3 @@ _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, return EGL_TRUE; } - - -/** - * Creates a set of \c __GLcontextModes that a driver will expose. - * - * A set of \c __GLcontextModes will be created based on the supplied - * parameters. The number of modes processed will be 2 * - * \c num_depth_stencil_bits * \c num_db_modes. - * - * For the most part, data is just copied from \c depth_bits, \c stencil_bits, - * \c db_modes, and \c visType into each \c __GLcontextModes element. - * However, the meanings of \c fb_format and \c fb_type require further - * explanation. The \c fb_format specifies which color components are in - * each pixel and what the default order is. For example, \c GL_RGB specifies - * that red, green, blue are available and red is in the "most significant" - * position and blue is in the "least significant". The \c fb_type specifies - * the bit sizes of each component and the actual ordering. For example, if - * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11] - * are the blue value, bits [10:5] are the green value, and bits [4:0] are - * the red value. - * - * One sublte issue is the combination of \c GL_RGB or \c GL_BGR and either - * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the - * \c __GLcontextModes structure is \b identical to the \c GL_RGBA or - * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as - * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8 - * still uses 32-bits. - * - * If in doubt, look at the tables used in the function. - * - * \param ptr_to_modes Pointer to a pointer to a linked list of - * \c __GLcontextModes. Upon completion, a pointer to - * the next element to be process will be stored here. - * If the function fails and returns \c GL_FALSE, this - * value will be unmodified, but some elements in the - * linked list may be modified. - * \param fb_format Format of the framebuffer. Currently only \c GL_RGB, - * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported. - * \param fb_type Type of the pixels in the framebuffer. Currently only - * \c GL_UNSIGNED_SHORT_5_6_5, - * \c GL_UNSIGNED_SHORT_5_6_5_REV, - * \c GL_UNSIGNED_INT_8_8_8_8, and - * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported. - * \param depth_bits Array of depth buffer sizes to be exposed. - * \param stencil_bits Array of stencil buffer sizes to be exposed. - * \param num_depth_stencil_bits Number of entries in both \c depth_bits and - * \c stencil_bits. - * \param db_modes Array of buffer swap modes. If an element has a - * value of \c GLX_NONE, then it represents a - * single-buffered mode. Other valid values are - * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and - * \c GLX_SWAP_UNDEFINED_OML. See the - * GLX_OML_swap_method extension spec for more details. - * \param num_db_modes Number of entries in \c db_modes. - * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or - * \c GLX_DIRECT_COLOR. - * - * \returns - * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only - * cause of failure is a bad parameter (i.e., unsupported \c fb_format or - * \c fb_type). - * - * \todo - * There is currently no way to support packed RGB modes (i.e., modes with - * exactly 3 bytes per pixel) or floating-point modes. This could probably - * be done by creating some new, private enums with clever names likes - * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32, - * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it. - */ -GLboolean -_eglFillInConfigs(_EGLConfig * configs, - GLenum fb_format, GLenum fb_type, - const uint8_t * depth_bits, const uint8_t * stencil_bits, - unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes, - int visType) -{ - static const uint8_t bits_table[3][4] = { - /* R G B A */ - { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */ - { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */ - { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */ - }; - - /* The following arrays are all indexed by the fb_type masked with 0x07. - * Given the four supported fb_type values, this results in valid array - * indices of 3, 4, 5, and 7. - */ - static const uint32_t masks_table_rgb[8][4] = { - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ - {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ - {0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000}, /* 8_8_8_8 */ - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000} /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_rgba[8][4] = { - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ - {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ - {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF}, /* 8_8_8_8 */ - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000}, /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_bgr[8][4] = { - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ - {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ - {0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000}, /* 8_8_8_8 */ - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000}, /* 8_8_8_8_REV */ - }; - - static const uint32_t masks_table_bgra[8][4] = { - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ - {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ - {0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF}, /* 8_8_8_8 */ - {0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, /* 8_8_8_8_REV */ - }; - - static const uint8_t bytes_per_pixel[8] = { - 0, 0, 0, 2, 2, 4, 0, 4 - }; - - const uint8_t * bits; - const uint32_t * masks; - const int index = fb_type & 0x07; - _EGLConfig *config; - unsigned i; - unsigned j; - unsigned k; - - if ( bytes_per_pixel[index] == 0 ) { - _eglLog(_EGL_INFO, - "[%s:%u] Framebuffer type 0x%04x has 0 bytes per pixel.", - __FUNCTION__, __LINE__, fb_type); - return GL_FALSE; - } - - /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and - * the _REV versions. - * - * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA. - */ - switch ( fb_format ) { - case GL_RGB: - bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; - masks = masks_table_rgb[index]; - break; - - case GL_RGBA: - bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; - masks = masks_table_rgba[index]; - break; - - case GL_BGR: - bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; - masks = masks_table_bgr[index]; - break; - - case GL_BGRA: - bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; - masks = masks_table_bgra[index]; - break; - - default: - _eglLog(_EGL_WARNING, - "[%s:%u] Framebuffer format 0x%04x is not GL_RGB, GL_RGBA, GL_BGR, or GL_BGRA.", - __FUNCTION__, __LINE__, fb_format); - return GL_FALSE; - } - - config = configs; - for (k = 0; k < num_depth_stencil_bits; k++) { - for (i = 0; i < num_db_modes; i++) { - for (j = 0; j < 2; j++) { - _eglSetConfigAttrib(config, EGL_RED_SIZE, bits[0]); - _eglSetConfigAttrib(config, EGL_GREEN_SIZE, bits[1]); - _eglSetConfigAttrib(config, EGL_BLUE_SIZE, bits[2]); - _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, bits[3]); - _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, - bits[0] + bits[1] + bits[2] + bits[3]); - - _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, stencil_bits[k]); - _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, depth_bits[i]); - - _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_SCREEN_BIT_MESA | - EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT); - - config++; - } - } - } - return GL_TRUE; -} diff --git a/src/egl/main/eglconfig.h b/src/egl/main/eglconfig.h index 441b3f4d20..db1c4c10e0 100644 --- a/src/egl/main/eglconfig.h +++ b/src/egl/main/eglconfig.h @@ -3,10 +3,10 @@ #include "egltypedefs.h" -#include "GL/internal/glcore.h" +#include <GLES/gl.h> -#define MAX_ATTRIBS 100 +#define MAX_ATTRIBS 128 #define FIRST_ATTRIB EGL_BUFFER_SIZE @@ -17,7 +17,11 @@ struct _egl_config }; -#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB] = VAL) +#define SET_CONFIG_ATTRIB(CONF, ATTR, VAL) \ + assert((ATTR) - FIRST_ATTRIB < MAX_ATTRIBS); \ + ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB] = VAL) + + #define GET_CONFIG_ATTRIB(CONF, ATTR) ((CONF)->Attrib[(ATTR) - FIRST_ATTRIB]) @@ -25,12 +29,16 @@ extern void _eglInitConfig(_EGLConfig *config, EGLint id); +extern EGLConfig +_eglGetConfigHandle(_EGLConfig *config); + + extern _EGLConfig * _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config); extern _EGLConfig * -_eglAddConfig(_EGLDisplay *display, const _EGLConfig *config); +_eglAddConfig(_EGLDisplay *display, _EGLConfig *config); extern EGLBoolean @@ -52,16 +60,5 @@ _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, EGLint confi extern void _eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val); -extern GLboolean -_eglFillInConfigs( _EGLConfig *configs, - GLenum fb_format, GLenum fb_type, - const uint8_t * depth_bits, const uint8_t * stencil_bits, - unsigned num_depth_stencil_bits, - const GLenum * db_modes, unsigned num_db_modes, - int visType ); - -extern void -_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode); - #endif /* EGLCONFIG_INCLUDED */ diff --git a/src/egl/main/eglconfigutil.c b/src/egl/main/eglconfigutil.c new file mode 100644 index 0000000000..7061df691b --- /dev/null +++ b/src/egl/main/eglconfigutil.c @@ -0,0 +1,258 @@ +/** + * Extra utility functions related to EGL configs. + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "eglconfigutil.h" +#include "egllog.h" + + +/** + * Convert an _EGLConfig to a __GLcontextModes object. + * NOTE: This routine may be incomplete - we're only making sure that + * the fields needed by Mesa (for _mesa_create_context/framebuffer) are + * set correctly. + */ +void +_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode) +{ + memset(mode, 0, sizeof(*mode)); + + mode->rgbMode = GL_TRUE; /* no color index */ + mode->colorIndexMode = GL_FALSE; + mode->doubleBufferMode = GL_TRUE; /* always DB for now */ + mode->stereoMode = GL_FALSE; + + mode->redBits = GET_CONFIG_ATTRIB(config, EGL_RED_SIZE); + mode->greenBits = GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE); + mode->blueBits = GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE); + mode->alphaBits = GET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE); + mode->rgbBits = GET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE); + + /* no rgba masks - fix? */ + + mode->depthBits = GET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE); + mode->haveDepthBuffer = mode->depthBits > 0; + + mode->stencilBits = GET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE); + mode->haveStencilBuffer = mode->stencilBits > 0; + + /* no accum */ + + mode->level = GET_CONFIG_ATTRIB(config, EGL_LEVEL); + mode->samples = GET_CONFIG_ATTRIB(config, EGL_SAMPLES); + mode->sampleBuffers = GET_CONFIG_ATTRIB(config, EGL_SAMPLE_BUFFERS); + + /* surface type - not really needed */ + mode->visualType = GLX_TRUE_COLOR; + mode->renderType = GLX_RGBA_BIT; +} + + + +/** + * Creates a set of \c _EGLConfigs that a driver will expose. + * + * A set of \c __GLcontextModes will be created based on the supplied + * parameters. The number of modes processed will be 2 * + * \c num_depth_stencil_bits * \c num_db_modes. + * + * For the most part, data is just copied from \c depth_bits, \c stencil_bits, + * \c db_modes, and \c visType into each \c __GLcontextModes element. + * However, the meanings of \c fb_format and \c fb_type require further + * explanation. The \c fb_format specifies which color components are in + * each pixel and what the default order is. For example, \c GL_RGB specifies + * that red, green, blue are available and red is in the "most significant" + * position and blue is in the "least significant". The \c fb_type specifies + * the bit sizes of each component and the actual ordering. For example, if + * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11] + * are the blue value, bits [10:5] are the green value, and bits [4:0] are + * the red value. + * + * One sublte issue is the combination of \c GL_RGB or \c GL_BGR and either + * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the + * \c __GLcontextModes structure is \b identical to the \c GL_RGBA or + * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as + * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8 + * still uses 32-bits. + * + * If in doubt, look at the tables used in the function. + * + * \param configs the array of configs generated + * \param fb_format Format of the framebuffer. Currently only \c GL_RGB, + * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported. + * \param fb_type Type of the pixels in the framebuffer. Currently only + * \c GL_UNSIGNED_SHORT_5_6_5, + * \c GL_UNSIGNED_SHORT_5_6_5_REV, + * \c GL_UNSIGNED_INT_8_8_8_8, and + * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported. + * \param depth_bits Array of depth buffer sizes to be exposed. + * \param stencil_bits Array of stencil buffer sizes to be exposed. + * \param num_depth_stencil_bits Number of entries in both \c depth_bits and + * \c stencil_bits. + * \param db_modes Array of buffer swap modes. If an element has a + * value of \c GLX_NONE, then it represents a + * single-buffered mode. Other valid values are + * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and + * \c GLX_SWAP_UNDEFINED_OML. See the + * GLX_OML_swap_method extension spec for more details. + * \param num_db_modes Number of entries in \c db_modes. + * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or + * \c GLX_DIRECT_COLOR. + * + * \returns + * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only + * cause of failure is a bad parameter (i.e., unsupported \c fb_format or + * \c fb_type). + * + * \todo + * There is currently no way to support packed RGB modes (i.e., modes with + * exactly 3 bytes per pixel) or floating-point modes. This could probably + * be done by creating some new, private enums with clever names likes + * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32, + * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it. + */ +EGLBoolean +_eglFillInConfigs(_EGLConfig * configs, + GLenum fb_format, GLenum fb_type, + const uint8_t * depth_bits, const uint8_t * stencil_bits, + unsigned num_depth_stencil_bits, + const GLenum * db_modes, unsigned num_db_modes, + int visType) +{ + static const uint8_t bits_table[3][4] = { + /* R G B A */ + { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */ + { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */ + { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */ + }; + + /* The following arrays are all indexed by the fb_type masked with 0x07. + * Given the four supported fb_type values, this results in valid array + * indices of 3, 4, 5, and 7. + */ + static const uint32_t masks_table_rgb[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ + {0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000} /* 8_8_8_8_REV */ + }; + + static const uint32_t masks_table_rgba[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5 */ + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5_REV */ + {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000}, /* 8_8_8_8_REV */ + }; + + static const uint32_t masks_table_bgr[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ + {0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000}, /* 8_8_8_8_REV */ + }; + + static const uint32_t masks_table_bgra[8][4] = { + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000001F, 0x000007E0, 0x0000F800, 0x00000000}, /* 5_6_5 */ + {0x0000F800, 0x000007E0, 0x0000001F, 0x00000000}, /* 5_6_5_REV */ + {0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF}, /* 8_8_8_8 */ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, /* 8_8_8_8_REV */ + }; + + static const uint8_t bytes_per_pixel[8] = { + 0, 0, 0, 2, 2, 4, 0, 4 + }; + + const uint8_t * bits; + const uint32_t * masks; + const int index = fb_type & 0x07; + _EGLConfig *config; + unsigned i; + unsigned j; + unsigned k; + + if ( bytes_per_pixel[index] == 0 ) { + _eglLog(_EGL_INFO, + "[%s:%u] Framebuffer type 0x%04x has 0 bytes per pixel.", + __FUNCTION__, __LINE__, fb_type); + return GL_FALSE; + } + + /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and + * the _REV versions. + * + * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA. + */ + switch ( fb_format ) { + case GL_RGB: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; + masks = masks_table_rgb[index]; + break; + + case GL_RGBA: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; + masks = masks_table_rgba[index]; + break; + +#if 0 + case GL_BGR: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[1]; + masks = masks_table_bgr[index]; + break; + + case GL_BGRA: + bits = (bytes_per_pixel[index] == 2) ? bits_table[0] : bits_table[2]; + masks = masks_table_bgra[index]; + break; +#endif + + default: + _eglLog(_EGL_WARNING, + "[%s:%u] Framebuffer format 0x%04x is not GL_RGB, GL_RGBA, GL_BGR, or GL_BGRA.", + __FUNCTION__, __LINE__, fb_format); + return GL_FALSE; + } + + config = configs; + for (k = 0; k < num_depth_stencil_bits; k++) { + for (i = 0; i < num_db_modes; i++) { + for (j = 0; j < 2; j++) { + _eglSetConfigAttrib(config, EGL_RED_SIZE, bits[0]); + _eglSetConfigAttrib(config, EGL_GREEN_SIZE, bits[1]); + _eglSetConfigAttrib(config, EGL_BLUE_SIZE, bits[2]); + _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, bits[3]); + _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, + bits[0] + bits[1] + bits[2] + bits[3]); + + _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, stencil_bits[k]); + _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, depth_bits[i]); + + _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_SCREEN_BIT_MESA | + EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT); + + config++; + } + } + } + return GL_TRUE; +} + diff --git a/src/egl/main/eglconfigutil.h b/src/egl/main/eglconfigutil.h new file mode 100644 index 0000000000..c477b94737 --- /dev/null +++ b/src/egl/main/eglconfigutil.h @@ -0,0 +1,26 @@ + +#ifndef EGLCONFIGUTIL_INCLUDED +#define EGLCONFIGUTIL_INCLUDED + +#include "eglconfig.h" +#include "GL/internal/glcore.h" +#if (!defined(WIN32) && !defined(_WIN32_WCE)) +#include "stdint.h" +#endif + + +extern void +_eglConfigToContextModesRec(const _EGLConfig *config, __GLcontextModes *mode); + + +extern EGLBoolean +_eglFillInConfigs( _EGLConfig *configs, + EGLenum fb_format, EGLenum fb_type, + const uint8_t * depth_bits, const uint8_t * stencil_bits, + unsigned num_depth_stencil_bits, + const EGLenum * db_modes, unsigned num_db_modes, + int visType ); + + + +#endif /* EGLCONFIGUTIL_INCLUDED */ diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index 374c006dae..461679db09 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -6,12 +6,12 @@ #include "egldisplay.h" #include "egldriver.h" #include "eglglobals.h" -#include "eglhash.h" #include "eglsurface.h" /** - * Initialize the given _EGLContext object to defaults. + * Initialize the given _EGLContext object to defaults and/or the values + * in the attrib_list. */ EGLBoolean _eglInitContext(_EGLDriver *drv, EGLDisplay dpy, _EGLContext *ctx, @@ -20,42 +20,54 @@ _eglInitContext(_EGLDriver *drv, EGLDisplay dpy, _EGLContext *ctx, _EGLConfig *conf; _EGLDisplay *display = _eglLookupDisplay(dpy); EGLint i; + const EGLenum api = eglQueryAPI(); + + if (api == EGL_NONE) { + _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)"); + return EGL_FALSE; + } conf = _eglLookupConfig(drv, dpy, config); if (!conf) { - _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + _eglError(EGL_BAD_CONFIG, "_eglInitContext"); return EGL_FALSE; } + memset(ctx, 0, sizeof(_EGLContext)); + + ctx->ClientVersion = 1; /* the default, per EGL spec */ + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { switch (attrib_list[i]) { - /* no attribs defined for now */ + case EGL_CONTEXT_CLIENT_VERSION: + i++; + ctx->ClientVersion = attrib_list[i]; + break; default: - _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext"); - return EGL_NO_CONTEXT; + _eglError(EGL_BAD_ATTRIBUTE, "_eglInitContext"); + return EGL_FALSE; } } - memset(ctx, 0, sizeof(_EGLContext)); ctx->Display = display; ctx->Config = conf; ctx->DrawSurface = EGL_NO_SURFACE; ctx->ReadSurface = EGL_NO_SURFACE; + ctx->ClientAPI = api; return EGL_TRUE; } -/* - * Assign an EGLContext handle to the _EGLContext object then put it into - * the hash table. +/** + * Save a new _EGLContext into the hash table. */ void _eglSaveContext(_EGLContext *ctx) { - assert(ctx); - ctx->Handle = _eglHashGenKey(_eglGlobal.Contexts); - _eglHashInsert(_eglGlobal.Contexts, ctx->Handle, ctx); + /* no-op. + * Public EGLContext handle and private _EGLContext are the same. + */ } @@ -65,19 +77,34 @@ _eglSaveContext(_EGLContext *ctx) void _eglRemoveContext(_EGLContext *ctx) { - _eglHashRemove(_eglGlobal.Contexts, ctx->Handle); + /* no-op. + * Public EGLContext handle and private _EGLContext are the same. + */ +} + + +/** + * Return the public handle for the given private context ptr. + * This is the inverse of _eglLookupContext(). + */ +EGLContext +_eglGetContextHandle(_EGLContext *ctx) +{ + /* just a cast! */ + return (EGLContext) ctx; } /** * Return the _EGLContext object that corresponds to the given * EGLContext handle. + * This is the inverse of _eglGetContextHandle(). */ _EGLContext * _eglLookupContext(EGLContext ctx) { - _EGLContext *c = (_EGLContext *) _eglHashLookup(_eglGlobal.Contexts, ctx); - return c; + /* just a cast since EGLContext is just a void ptr */ + return (_EGLContext *) ctx; } @@ -112,7 +139,7 @@ _eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, } _eglSaveContext(context); - return context->Handle; + return (EGLContext) context; #endif return EGL_NO_CONTEXT; } @@ -126,7 +153,6 @@ _eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx) { _EGLContext *context = _eglLookupContext(ctx); if (context) { - _eglHashRemove(_eglGlobal.Contexts, ctx); if (context->IsBound) { context->DeletePending = EGL_TRUE; } @@ -163,8 +189,11 @@ _eglQueryContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx, #ifdef EGL_VERSION_1_2 case EGL_CONTEXT_CLIENT_TYPE: *value = c->ClientAPI; - return EGL_FALSE; + return EGL_TRUE; #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; @@ -239,7 +268,7 @@ _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, ctx = NULL; } /* really delete context now */ - drv->API.DestroyContext(drv, dpy, oldContext->Handle); + drv->API.DestroyContext(drv, dpy, _eglGetContextHandle(oldContext)); } } diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h index 82bfde151f..34fee9c637 100644 --- a/src/egl/main/eglcontext.h +++ b/src/egl/main/eglcontext.h @@ -11,8 +11,6 @@ */ struct _egl_context { - EGLContext Handle; /* The public/opaque handle which names this object */ - _EGLDisplay *Display; /* who do I belong to? */ _EGLConfig *Config; @@ -22,9 +20,9 @@ struct _egl_context EGLBoolean IsBound; EGLBoolean DeletePending; -#ifdef EGL_VERSION_1_2 - EGLint ClientAPI; /* Either EGL_OPENGL_ES_API or EGL_OPENVG_API */ -#endif /* EGL_VERSION_1_2 */ + + EGLint ClientAPI; /**< EGL_OPENGL_ES_API, EGL_OPENGL_API, EGL_OPENVG_API */ + EGLint ClientVersion; /**< 1 = OpenGLES 1.x, 2 = OpenGLES 2.x */ }; @@ -41,6 +39,10 @@ extern void _eglRemoveContext(_EGLContext *ctx); +extern EGLContext +_eglGetContextHandle(_EGLContext *ctx); + + extern _EGLContext * _eglLookupContext(EGLContext ctx); diff --git a/src/egl/main/egldefines.h b/src/egl/main/egldefines.h new file mode 100644 index 0000000000..8fc2301b79 --- /dev/null +++ b/src/egl/main/egldefines.h @@ -0,0 +1,45 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + + +/** + * Internal EGL defines + */ + + +#ifndef EGLDEFINES_INCLUDED +#define EGLDEFINES_INCLUDED + + +#define _EGL_MAX_EXTENSIONS_LEN 1000 + +#define _EGL_VENDOR_STRING "Mesa Project" + + + +#endif /* EGLDEFINES_INCLUDED */ diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index 074a85bf26..47a2323eaf 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -1,52 +1,88 @@ + +/** + * Functions related to EGLDisplay. + */ + +#include <assert.h> #include <stdlib.h> #include <string.h> #include "eglcontext.h" #include "egldisplay.h" +#include "egldriver.h" #include "eglglobals.h" #include "eglhash.h" - - -static char * -my_strdup(const char *s) -{ - int l = strlen(s); - char *s2 = malloc(l + 1); - strcpy(s2, s); - return s2; -} +#include "eglstring.h" /** - * We're assuming that the NativeDisplayType parameter is actually - * a string. - * Return a new _EGLDisplay object for the given displayName + * Allocate a new _EGLDisplay object for the given nativeDisplay handle. + * We'll also try to determine the device driver name at this time. + * + * Note that nativeDisplay may be an X Display ptr, or a string. */ _EGLDisplay * -_eglNewDisplay(NativeDisplayType displayName) +_eglNewDisplay(NativeDisplayType nativeDisplay) { _EGLDisplay *dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay)); if (dpy) { - dpy->Handle = _eglHashGenKey(_eglGlobal.Displays); - _eglHashInsert(_eglGlobal.Displays, dpy->Handle, dpy); - if (displayName) - dpy->Name = my_strdup(displayName); - else - dpy->Name = NULL; - dpy->Driver = NULL; /* this gets set later */ + EGLuint key = _eglHashGenKey(_eglGlobal.Displays); + + dpy->Handle = (EGLDisplay) key; + _eglHashInsert(_eglGlobal.Displays, key, dpy); + + dpy->NativeDisplay = nativeDisplay; +#if defined(_EGL_PLATFORM_X) + dpy->Xdpy = (Display *) nativeDisplay; +#endif + + dpy->DriverName = _eglChooseDriver(dpy); + if (!dpy->DriverName) { + free(dpy); + return NULL; + } } return dpy; } /** + * Return the public handle for an internal _EGLDisplay. + * This is the inverse of _eglLookupDisplay(). + */ +EGLDisplay +_eglGetDisplayHandle(_EGLDisplay *display) +{ + if (display) + return display->Handle; + else + return EGL_NO_DISPLAY; +} + + +/** * Return the _EGLDisplay object that corresponds to the given public/ * opaque display handle. + * This is the inverse of _eglGetDisplayHandle(). */ _EGLDisplay * _eglLookupDisplay(EGLDisplay dpy) { - _EGLDisplay *d = (_EGLDisplay *) _eglHashLookup(_eglGlobal.Displays, dpy); - return d; + EGLuint key = (EGLuint) dpy; + if (!_eglGlobal.Displays) + return NULL; + return (_EGLDisplay *) _eglHashLookup(_eglGlobal.Displays, key); +} + + +void +_eglSaveDisplay(_EGLDisplay *dpy) +{ + EGLuint key = _eglHashGenKey(_eglGlobal.Displays); + assert(dpy); + assert(!dpy->Handle); + dpy->Handle = (EGLDisplay) key; + assert(dpy->Handle); + _eglHashInsert(_eglGlobal.Displays, key, dpy); } @@ -61,11 +97,25 @@ _eglGetCurrentDisplay(void) } +/** + * Free all the data hanging of an _EGLDisplay object, but not + * the object itself. + */ void _eglCleanupDisplay(_EGLDisplay *disp) { - /* XXX incomplete */ + EGLint i; + + for (i = 0; i < disp->NumConfigs; i++) { + free(disp->Configs[i]); + } free(disp->Configs); - free(disp->Name); - /* driver deletes _EGLDisplay */ + disp->Configs = NULL; + + /* XXX incomplete */ + + free((void *) disp->DriverName); + disp->DriverName = NULL; + + /* driver deletes the _EGLDisplay object */ } diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 1a03fdd4ad..ff623ee1c6 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -1,22 +1,31 @@ #ifndef EGLDISPLAY_INCLUDED #define EGLDISPLAY_INCLUDED +#ifdef _EGL_PLATFORM_X +#include <X11/Xlib.h> +#endif #include "egltypedefs.h" struct _egl_display { + EGLNativeDisplayType NativeDisplay; EGLDisplay Handle; - char *Name; + const char *DriverName; + const char *DriverArgs; _EGLDriver *Driver; EGLint NumScreens; _EGLScreen **Screens; /* array [NumScreens] */ EGLint NumConfigs; - _EGLConfig *Configs; /* array [NumConfigs] */ + _EGLConfig **Configs; /* array [NumConfigs] of ptr to _EGLConfig */ + +#ifdef _EGL_PLATFORM_X + Display *Xdpy; +#endif }; @@ -24,10 +33,18 @@ extern _EGLDisplay * _eglNewDisplay(NativeDisplayType displayName); +EGLDisplay +_eglGetDisplayHandle(_EGLDisplay *display); + + extern _EGLDisplay * _eglLookupDisplay(EGLDisplay dpy); +extern void +_eglSaveDisplay(_EGLDisplay *dpy); + + extern _EGLDisplay * _eglGetCurrentDisplay(void); diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c index bda06dd827..43b1f51903 100644 --- a/src/egl/main/egldriver.c +++ b/src/egl/main/egldriver.c @@ -1,112 +1,277 @@ +/** + * Functions for choosing and opening/loading device drivers. + */ + + #include <assert.h> -#include <dlfcn.h> -#include <stdio.h> #include <string.h> +#include <stdio.h> +#include <stdlib.h> #include "eglconfig.h" #include "eglcontext.h" +#include "egldefines.h" #include "egldisplay.h" #include "egldriver.h" #include "eglglobals.h" #include "egllog.h" +#include "eglmisc.h" #include "eglmode.h" #include "eglscreen.h" +#include "eglstring.h" #include "eglsurface.h" +#if defined(_EGL_PLATFORM_X) +#include <dlfcn.h> +#include "eglx.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 + static const char *SysFS = NULL; + 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 + } + +#elif defined(_EGL_PLATFORM_X) + static const char *DefaultDriverName = ":0"; + static const char *SysFS = "/sys/class"; + + typedef void * lib_handle; + + static void * + open_library(const char *filename) + { + return dlopen(filename, RTLD_LAZY); + } + + static void + close_library(void *lib) + { + dlclose(lib); + } + +#endif + +/** + * Given a card number, use sysfs to determine the DRI driver name. + */ +const char * +_eglChooseDRMDriver(int card) +{ +#if 0 + return _eglstrdup("libEGLdri"); +#else + char path[2000], driverName[2000]; + FILE *f; + int length; + + snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", SysFS, card); + + f = fopen(path, "r"); + if (!f) + return NULL; -const char *DefaultDriverName = "demodriver"; + fgets(driverName, sizeof(driverName), f); + fclose(f); + if ((length = strlen(driverName)) > 1) { + /* remove the trailing newline from sysfs */ + driverName[length - 1] = '\0'; + strncat(driverName, "_dri", sizeof(driverName)); + return _eglstrdup(driverName); + } + else { + return NULL; + } +#endif +} /** - * Choose and open/init the hardware driver for the given EGLDisplay. - * Previously, the EGLDisplay was created with _eglNewDisplay() where - * we recorded the user's NativeDisplayType parameter. + * XXX this function is totally subject change!!! + * + * + * Determine/return the name of the driver to use for the given _EGLDisplay. * - * Now we'll use the NativeDisplayType value. + * Try to be clever and determine if nativeDisplay is an Xlib Display + * ptr or a string (naming a driver or screen number, etc). * - * Currently, the native display value is treated as a string. * If the first character is ':' we interpret it as a screen or card index * number (i.e. ":0" or ":1", etc) * Else if the first character is '!' we interpret it as specific driver name * (i.e. "!r200" or "!i830". + * + * Whatever follows ':' is copied and put into dpy->DriverArgs. + * + * The caller may free() the returned string. */ -_EGLDriver * -_eglChooseDriver(EGLDisplay display) +const char * +_eglChooseDriver(_EGLDisplay *dpy) { - _EGLDisplay *dpy = _eglLookupDisplay(display); - _EGLDriver *drv; - const char *driverName = DefaultDriverName; - const char *name; + /* Under Windows, the NativeDisplay is an HDC handle, therefore */ + /* it can't be interpreted as a string or a pointer. */ +#if defined(_EGL_PLATFORM_WINDOWS) + const char *displayString = NULL; +#else + const char *displayString = (const char *) dpy->NativeDisplay; +#endif + const char *driverName = NULL; - assert(dpy); + (void) DefaultDriverName; - name = dpy->Name; - if (!name) { - /* use default */ +#if defined(_EGL_PLATFORM_X) + /* First, if the EGL_DRIVER env var is set, use that */ + driverName = getenv("EGL_DRIVER"); + if (driverName) + return _eglstrdup(driverName); +#endif + +#if 0 + if (!displayString) { + /* choose a default */ + displayString = DefaultDriverName; } - else if (name[0] == ':' && (name[1] >= '0' && name[1] <= '9') && !name[2]) { - /* XXX probe hardware here to determine which driver to open */ - driverName = "libEGLdri"; +#endif + /* extract default DriverArgs = whatever follows ':' */ + if (displayString && + (displayString[0] == '!' || + displayString[0] == ':')) { + const char *args = strchr(displayString, ':'); + if (args) + dpy->DriverArgs = _eglstrdup(args + 1); } - else if (name[0] == '!') { - /* use specified driver name */ - driverName = name + 1; + + /* determine driver name now */ + if (displayString && displayString[0] == ':' && + (displayString[1] >= '0' && displayString[1] <= '9') && + !displayString[2]) { + int card = atoi(displayString + 1); + driverName = _eglChooseDRMDriver(card); } - else { - /* Maybe display was returned by XOpenDisplay? */ - _eglLog(_EGL_FATAL, "eglChooseDriver() bad name"); + else if (displayString && displayString[0] == '!') { + /* use user-specified driver name */ + driverName = _eglstrdup(displayString + 1); + /* truncate driverName at ':' if present */ + { + char *args = strchr(driverName, ':'); + if (args) { + *args = 0; + } + } + } + else + { + /* NativeDisplay is not a string! */ +#if defined(_EGL_PLATFORM_X) + driverName = _xeglChooseDriver(dpy); +#else + driverName = DefaultDriverName; +#endif } - _eglLog(_EGL_INFO, "eglChooseDriver() choosing %s", driverName); - - drv = _eglOpenDriver(dpy, driverName); - dpy->Driver = drv; - - return drv; + return driverName; } /** * Open/load the named driver and call its bootstrap function: _eglMain(). + * By the time this function is called, the dpy->DriverName should have + * been determined. + * * \return new _EGLDriver object. */ _EGLDriver * -_eglOpenDriver(_EGLDisplay *dpy, const char *driverName) +_eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args) { _EGLDriver *drv; _EGLMain_t mainFunc; - void *lib; + lib_handle lib; char driverFilename[1000]; + assert(driverName); + +#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 */ + sprintf(driverFilename, "%s.dll", driverName); + _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename); + lib = open_library(driverFilename); + if (!lib) { + _eglLog(_EGL_WARNING, "Could not open %s", + driverFilename); + return NULL; + } + mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain"); +#endif +#elif defined(_EGL_PLATFORM_X) /* XXX also prepend a directory path??? */ sprintf(driverFilename, "%s.so", driverName); - _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename); - lib = dlopen(driverFilename, RTLD_NOW); + lib = open_library(driverFilename); if (!lib) { _eglLog(_EGL_WARNING, "Could not open %s (%s)", driverFilename, dlerror()); return NULL; } - mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain"); +#endif + if (!mainFunc) { _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename); - dlclose(lib); + close_library(lib); return NULL; } - drv = mainFunc(dpy); + drv = mainFunc(dpy, args); if (!drv) { - dlclose(lib); + close_library(lib); return NULL; } + /* with a recurvise open you want the inner most handle */ - if (!drv->LibHandle) + if (!drv->LibHandle) { drv->LibHandle = lib; - else - dlclose(lib); + } + else { + close_library(lib); + } + + /* update the global notion of supported APIs */ + _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask; + + _eglSaveDriver(drv); - drv->Display = dpy; return drv; } @@ -117,19 +282,31 @@ _eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy) void *handle = drv->LibHandle; EGLBoolean b; - _eglLog(_EGL_INFO, "Closing driver"); + _eglLog(_EGL_DEBUG, "Closing %s", drv->Name); /* * XXX check for currently bound context/surfaces and delete them? */ b = drv->API.Terminate(drv, dpy); - dlclose(handle); + + close_library(handle); + return b; } /** + * Save the given driver pointer in the list of all known drivers. + */ +void +_eglSaveDriver(_EGLDriver *drv) +{ + _eglGlobal.Drivers[ _eglGlobal.NumDrivers++ ] = drv; +} + + +/** * Given a display handle, return the _EGLDriver for that display. */ _EGLDriver * @@ -201,72 +378,48 @@ _eglInitDriverFallbacks(_EGLDriver *drv) } + /** - * Examine the individual extension enable/disable flags and recompute - * the driver's Extensions string. + * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc) + * are supported on the system by looking for standard library names. */ -static void -_eglUpdateExtensionsString(_EGLDriver *drv) -{ - drv->Extensions.String[0] = 0; - - if (drv->Extensions.MESA_screen_surface) - strcat(drv->Extensions.String, "EGL_MESA_screen_surface "); - if (drv->Extensions.MESA_copy_context) - strcat(drv->Extensions.String, "EGL_MESA_copy_context "); - assert(strlen(drv->Extensions.String) < MAX_EXTENSIONS_LEN); -} - - - -const char * -_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name) +EGLint +_eglFindAPIs(void) { - (void) drv; - (void) dpy; - switch (name) { - case EGL_VENDOR: - return "Mesa Project"; - case EGL_VERSION: - return "1.0"; - case EGL_EXTENSIONS: - _eglUpdateExtensionsString(drv); - return drv->Extensions.String; -#ifdef EGL_VERSION_1_2 - case EGL_CLIENT_APIS: - /* XXX need to initialize somewhere */ - return drv->ClientAPIs; + EGLint mask = 0x0; + lib_handle lib; +#if defined(_EGL_PLATFORM_WINDOWS) + /* XXX not sure about these names */ + const char *es1_libname = "libGLESv1_CM.dll"; + const char *es2_libname = "libGLESv2.dll"; + const char *gl_libname = "OpenGL32.dll"; + const char *vg_libname = "libOpenVG.dll"; +#elif defined(_EGL_PLATFORM_X) + const char *es1_libname = "libGLESv1_CM.so"; + const char *es2_libname = "libGLESv2.so"; + const char *gl_libname = "libGL.so"; + const char *vg_libname = "libOpenVG.so"; #endif - default: - _eglError(EGL_BAD_PARAMETER, "eglQueryString"); - return NULL; - } -} + if ((lib = open_library(es1_libname))) { + close_library(lib); + mask |= EGL_OPENGL_ES_BIT; + } -EGLBoolean -_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy) -{ - /* just a placeholder */ - (void) drv; - (void) dpy; - return EGL_TRUE; -} + if ((lib = open_library(es2_libname))) { + close_library(lib); + mask |= EGL_OPENGL_ES2_BIT; + } + if ((lib = open_library(gl_libname))) { + close_library(lib); + mask |= EGL_OPENGL_BIT; + } -EGLBoolean -_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine) -{ - /* just a placeholder */ - (void) drv; - (void) dpy; - switch (engine) { - case EGL_CORE_NATIVE_ENGINE: - break; - default: - _eglError(EGL_BAD_PARAMETER, "eglWaitNative(engine)"); - return EGL_FALSE; + if ((lib = open_library(vg_libname))) { + close_library(lib); + mask |= EGL_OPENVG_BIT; } - return EGL_TRUE; + return mask; } diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h index 88526e973d..4066c6ec1d 100644 --- a/src/egl/main/egldriver.h +++ b/src/egl/main/egldriver.h @@ -4,9 +4,7 @@ #include "egltypedefs.h" #include "eglapi.h" - -/* should probably use a dynamic-length string, but this will do */ -#define MAX_EXTENSIONS_LEN 1000 +#include "egldefines.h" /** @@ -17,7 +15,7 @@ struct _egl_extensions EGLBoolean MESA_screen_surface; EGLBoolean MESA_copy_context; - char String[MAX_EXTENSIONS_LEN]; + char String[_EGL_MAX_EXTENSIONS_LEN]; }; @@ -26,37 +24,48 @@ struct _egl_extensions */ struct _egl_driver { - EGLBoolean Initialized; /* set by driver after initialized */ + EGLBoolean Initialized; /**< set by driver after initialized */ + + void *LibHandle; /**< dlopen handle */ - void *LibHandle; /* dlopen handle */ + const char *Name; /**< name of this driver */ - _EGLDisplay *Display; + int APImajor, APIminor; /**< as returned by eglInitialize() */ + char Version[1000]; /**< initialized from APImajor/minor, Name */ - int ABIversion; - int APImajor, APIminor; /* returned through eglInitialize */ - const char *ClientAPIs; + /** Bitmask of supported APIs (EGL_xx_BIT) set by the driver during init */ + EGLint ClientAPIsMask; - _EGLAPI API; + _EGLAPI API; /**< EGL API dispatch table */ _EGLExtensions Extensions; + + int LargestPbuffer; }; -extern _EGLDriver *_eglMain(_EGLDisplay *dpy); +extern _EGLDriver *_eglMain(_EGLDisplay *dpy, const char *args); -extern _EGLDriver * -_eglChooseDriver(EGLDisplay dpy); +extern const char * +_eglChooseDRMDriver(int card); + +extern const char * +_eglChooseDriver(_EGLDisplay *dpy); extern _EGLDriver * -_eglOpenDriver(_EGLDisplay *dpy, const char *driverName); +_eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args); extern EGLBoolean _eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy); +extern void +_eglSaveDriver(_EGLDriver *drv); + + extern _EGLDriver * _eglLookupDriver(EGLDisplay d); @@ -65,17 +74,8 @@ extern void _eglInitDriverFallbacks(_EGLDriver *drv); -extern const char * -_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name); - - -extern EGLBoolean -_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy); - - -extern EGLBoolean -_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine); - +extern EGLint +_eglFindAPIs(void); #endif /* EGLDRIVER_INCLUDED */ diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c index 608311d749..b770e55dbd 100644 --- a/src/egl/main/eglglobals.c +++ b/src/egl/main/eglglobals.c @@ -2,9 +2,10 @@ #include <stdlib.h> #include "eglglobals.h" - -struct _egl_global _eglGlobal = { .Initialized = EGL_FALSE }; - +struct _egl_global _eglGlobal = +{ + EGL_FALSE +}; /** * Init the fields in the _eglGlobal struct @@ -15,13 +16,11 @@ _eglInitGlobals(void) { if (!_eglGlobal.Initialized) { _eglGlobal.Displays = _eglNewHashTable(); - _eglGlobal.Contexts = _eglNewHashTable(); _eglGlobal.Surfaces = _eglNewHashTable(); _eglGlobal.FreeScreenHandle = 1; _eglGlobal.Initialized = EGL_TRUE; - _eglGlobal.OpenGLESAPISupported = EGL_TRUE; - _eglGlobal.OpenVGAPISupported = EGL_FALSE; + _eglGlobal.ClientAPIsMask = 0x0; /* XXX temporary */ _eglGlobal.ThreadInfo = _eglNewThreadInfo(); @@ -37,7 +36,6 @@ _eglDestroyGlobals(void) { /* XXX TODO walk over table entries, deleting each */ _eglDeleteHashTable(_eglGlobal.Displays); - _eglDeleteHashTable(_eglGlobal.Contexts); _eglDeleteHashTable(_eglGlobal.Surfaces); } @@ -52,7 +50,7 @@ _eglNewThreadInfo(void) if (t) { t->CurrentContext = EGL_NO_CONTEXT; t->LastError = EGL_SUCCESS; - t->CurrentAPI = EGL_NONE; + t->CurrentAPI = EGL_OPENGL_ES_API; /* default, per EGL spec */ } return t; } diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h index c16baa2d6b..14d8ea487a 100644 --- a/src/egl/main/eglglobals.h +++ b/src/egl/main/eglglobals.h @@ -24,17 +24,20 @@ struct _egl_global EGLBoolean Initialized; _EGLHashtable *Displays; - _EGLHashtable *Contexts; _EGLHashtable *Surfaces; EGLScreenMESA FreeScreenHandle; - /* XXX these may be temporary */ - EGLBoolean OpenGLESAPISupported; - EGLBoolean OpenVGAPISupported; + /* bitmaks of supported APIs (supported by _some_ driver) */ + EGLint ClientAPIsMask; + + char ClientAPIs[1000]; /**< updated by eglQueryString */ /* XXX temporary - should be thread-specific data (TSD) */ _EGLThreadInfo *ThreadInfo; + + EGLint NumDrivers; + _EGLDriver *Drivers[10]; }; diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c index dc1daaa996..1d7a0a388c 100644 --- a/src/egl/main/egllog.c +++ b/src/egl/main/egllog.c @@ -1,5 +1,7 @@ /** * Logging facility for debug/info messages. + * _EGL_FATAL messages are printed to stderr + * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs. */ @@ -10,37 +12,41 @@ #include "egllog.h" #define MAXSTRING 1000 -#define FALLBACK_LOG_LEVEL _EGL_DEBUG -#define FALLBACK_LOG_LEVEL_STR "debug" +#define FALLBACK_LOG_LEVEL _EGL_WARNING +#define FALLBACK_LOG_LEVEL_STR "warning" static EGLint ReportingLevel = -1; static void -log_level_initialize (void) +log_level_initialize(void) { - char *log_env = getenv ("EGL_LOG_LEVEL"); +#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) { + else if (strcasecmp(log_env, "fatal") == 0) { ReportingLevel = _EGL_FATAL; } - else if (strcasecmp (log_env, "warning") == 0) { + else if (strcasecmp(log_env, "warning") == 0) { ReportingLevel = _EGL_WARNING; } - else if (strcasecmp (log_env, "info") == 0) { + else if (strcasecmp(log_env, "info") == 0) { ReportingLevel = _EGL_INFO; } - else if (strcasecmp (log_env, "debug") == 0) { + else if (strcasecmp(log_env, "debug") == 0) { ReportingLevel = _EGL_DEBUG; } else { - fprintf (stderr, "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); + fprintf(stderr, "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; } } @@ -59,7 +65,7 @@ _eglLog(EGLint level, const char *fmtStr, ...) static int log_level_initialized = 0; if (!log_level_initialized) { - log_level_initialize (); + log_level_initialize(); log_level_initialized = 1; } @@ -85,7 +91,7 @@ _eglLog(EGLint level, const char *fmtStr, ...) vsnprintf(msg, MAXSTRING, fmtStr, args); va_end(args); - fprintf(stderr, "EGL %s: %s\n", levelStr, msg); + fprintf(stderr, "libEGL %s: %s\n", levelStr, msg); if (level == _EGL_FATAL) { exit(1); /* or abort()? */ diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c new file mode 100644 index 0000000000..b5bdc3ea4b --- /dev/null +++ b/src/egl/main/eglmisc.c @@ -0,0 +1,129 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * Small/misc EGL functions + */ + + +#include <assert.h> +#include <string.h> +#include "eglglobals.h" +#include "eglmisc.h" + + +/** + * Examine the individual extension enable/disable flags and recompute + * the driver's Extensions string. + */ +static void +_eglUpdateExtensionsString(_EGLDriver *drv) +{ + drv->Extensions.String[0] = 0; + + if (drv->Extensions.MESA_screen_surface) + strcat(drv->Extensions.String, "EGL_MESA_screen_surface "); + if (drv->Extensions.MESA_copy_context) + strcat(drv->Extensions.String, "EGL_MESA_copy_context "); + assert(strlen(drv->Extensions.String) < _EGL_MAX_EXTENSIONS_LEN); +} + + +static void +_eglUpdateAPIsString(_EGLDriver *drv) +{ + _eglGlobal.ClientAPIs[0] = 0; + + if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_BIT) + strcat(_eglGlobal.ClientAPIs, "OpenGL "); + + if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_ES_BIT) + strcat(_eglGlobal.ClientAPIs, "OpenGL_ES "); + + if (_eglGlobal.ClientAPIsMask & EGL_OPENGL_ES2_BIT) + strcat(_eglGlobal.ClientAPIs, "OpenGL_ES2 "); + + if (_eglGlobal.ClientAPIsMask & EGL_OPENVG_BIT) + strcat(_eglGlobal.ClientAPIs, "OpenVG "); + + assert(strlen(_eglGlobal.ClientAPIs) < sizeof(_eglGlobal.ClientAPIs)); +} + + + +const char * +_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name) +{ + (void) drv; + (void) dpy; + switch (name) { + case EGL_VENDOR: + return _EGL_VENDOR_STRING; + case EGL_VERSION: + return drv->Version; + case EGL_EXTENSIONS: + _eglUpdateExtensionsString(drv); + return drv->Extensions.String; +#ifdef EGL_VERSION_1_2 + case EGL_CLIENT_APIS: + _eglUpdateAPIsString(drv); + return _eglGlobal.ClientAPIs; +#endif + default: + _eglError(EGL_BAD_PARAMETER, "eglQueryString"); + return NULL; + } +} + + +EGLBoolean +_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy) +{ + /* just a placeholder */ + (void) drv; + (void) dpy; + return EGL_TRUE; +} + + +EGLBoolean +_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine) +{ + /* just a placeholder */ + (void) drv; + (void) dpy; + switch (engine) { + case EGL_CORE_NATIVE_ENGINE: + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglWaitNative(engine)"); + return EGL_FALSE; + } + + return EGL_TRUE; +} diff --git a/src/egl/main/eglmisc.h b/src/egl/main/eglmisc.h new file mode 100644 index 0000000000..4e2a40ea99 --- /dev/null +++ b/src/egl/main/eglmisc.h @@ -0,0 +1,47 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef EGLMISC_INCLUDED +#define EGLMISC_INCLUDED + +#include "egldriver.h" + + +extern const char * +_eglQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name); + + +extern EGLBoolean +_eglWaitGL(_EGLDriver *drv, EGLDisplay dpy); + + +extern EGLBoolean +_eglWaitNative(_EGLDriver *drv, EGLDisplay dpy, EGLint engine); + + +#endif /* EGLMISC_INCLUDED */ diff --git a/src/egl/main/eglmode.h b/src/egl/main/eglmode.h index e70da85759..52d4875676 100644 --- a/src/egl/main/eglmode.h +++ b/src/egl/main/eglmode.h @@ -4,6 +4,9 @@ #include "egltypedefs.h" +#define EGL_NO_MODE_MESA 0 + + /** * Data structure which corresponds to an EGLModeMESA. */ diff --git a/src/egl/main/eglstring.c b/src/egl/main/eglstring.c new file mode 100644 index 0000000000..ba7406158c --- /dev/null +++ b/src/egl/main/eglstring.c @@ -0,0 +1,24 @@ +/** + * String utils. + */ + +#include <stdlib.h> +#include <string.h> +#include "eglstring.h" + + +char * +_eglstrdup(const char *s) +{ + if (s) { + int l = strlen(s); + char *s2 = malloc(l + 1); + if (s2) + strcpy(s2, s); + return s2; + } + return NULL; +} + + + diff --git a/src/egl/main/eglstring.h b/src/egl/main/eglstring.h new file mode 100644 index 0000000000..10468636e8 --- /dev/null +++ b/src/egl/main/eglstring.h @@ -0,0 +1,9 @@ +#ifndef EGLSTRING_INCLUDED +#define EGLSTRING_INCLUDED + + +extern char * +_eglstrdup(const char *s); + + +#endif /* EGLSTRING_INCLUDED */ diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c index 874f318e96..6905acac50 100644 --- a/src/egl/main/eglsurface.c +++ b/src/egl/main/eglsurface.c @@ -8,6 +8,7 @@ #include <string.h> #include "eglcontext.h" #include "eglconfig.h" +#include "egldriver.h" #include "eglglobals.h" #include "eglhash.h" #include "egllog.h" @@ -60,6 +61,12 @@ _eglInitSurface(_EGLDriver *drv, EGLDisplay dpy, return EGL_FALSE; } + if ((GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE) & type) == 0) { + /* The config can't be used to create a surface of this type */ + _eglError(EGL_BAD_CONFIG, func); + return EGL_FALSE; + } + /* * Parse attribute list. Different kinds of surfaces support different * attributes. @@ -175,7 +182,7 @@ _eglInitSurface(_EGLDriver *drv, EGLDisplay dpy, } } - if (width <= 0 || height <= 0) { + if (width < 0 || height < 0) { _eglError(EGL_BAD_ATTRIBUTE, func); return EGL_FALSE; } @@ -207,25 +214,47 @@ _eglInitSurface(_EGLDriver *drv, EGLDisplay dpy, void _eglSaveSurface(_EGLSurface *surf) { + EGLuint key = _eglHashGenKey(_eglGlobal.Surfaces); assert(surf); assert(!surf->Handle); - surf->Handle = _eglHashGenKey(_eglGlobal.Contexts); + surf->Handle = (EGLSurface) key; assert(surf->Handle); - _eglHashInsert(_eglGlobal.Surfaces, surf->Handle, surf); + _eglHashInsert(_eglGlobal.Surfaces, key, surf); } void _eglRemoveSurface(_EGLSurface *surf) { - _eglHashRemove(_eglGlobal.Surfaces, surf->Handle); + _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surf->Handle); +} + + + +/** + * Return the public handle for an internal _EGLSurface. + * This is the inverse of _eglLookupSurface(). + */ +EGLSurface +_eglGetSurfaceHandle(_EGLSurface *surface) +{ + if (surface) + return surface->Handle; + else + return EGL_NO_SURFACE; } +/** + * Return the private _EGLSurface which corresponds to a public EGLSurface + * handle. + * This is the inverse of _eglGetSurfaceHandle(). + */ _EGLSurface * _eglLookupSurface(EGLSurface surf) { - _EGLSurface *c = (_EGLSurface *) _eglHashLookup(_eglGlobal.Surfaces, surf); + _EGLSurface *c = (_EGLSurface *) _eglHashLookup(_eglGlobal.Surfaces, + (EGLuint) surf); return c; } @@ -254,12 +283,7 @@ _eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) /* Basically just do error checking here. Drivers have to do the * actual buffer swap. */ - _EGLContext *context = _eglGetCurrentContext(); _EGLSurface *surface = _eglLookupSurface(draw); - if (context && context->DrawSurface != surface) { - _eglError(EGL_BAD_SURFACE, "eglSwapBuffers"); - return EGL_FALSE; - } if (surface == NULL) { _eglError(EGL_BAD_SURFACE, "eglSwapBuffers"); return EGL_FALSE; @@ -297,7 +321,9 @@ _eglQuerySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, case EGL_CONFIG_ID: *value = GET_CONFIG_ATTRIB(surface->Config, EGL_CONFIG_ID); return EGL_TRUE; - /*XXX case EGL_LARGEST_PBUFFER:*/ + case EGL_LARGEST_PBUFFER: + *value = drv->LargestPbuffer; + return EGL_TRUE; case EGL_SURFACE_TYPE: *value = surface->Type; return EGL_TRUE; @@ -439,7 +465,7 @@ _eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) { _EGLSurface *surf = _eglLookupSurface(surface); if (surf) { - _eglHashRemove(_eglGlobal.Surfaces, surface); + _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface); if (surf->IsBound) { surf->DeletePending = EGL_TRUE; } @@ -459,7 +485,8 @@ _eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface) * Default fallback routine - drivers might override this. */ EGLBoolean -_eglSurfaceAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, EGLint attribute, EGLint value) +_eglSurfaceAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, + EGLint attribute, EGLint value) { _EGLSurface *surface = _eglLookupSurface(surf); @@ -481,18 +508,67 @@ _eglSurfaceAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, EGLint attri EGLBoolean -_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer) +_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, + EGLint buffer) { - /* XXX unfinished */ - return EGL_FALSE; + /* Just do basic error checking and return success/fail. + * Drivers must implement the real stuff. + */ + _EGLSurface *surface = _eglLookupSurface(surf); + + if (!surface || surface->Type != EGL_PBUFFER_BIT) { + _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); + return EGL_FALSE; + } + + if (surface->TextureFormat == EGL_NO_TEXTURE) { + _eglError(EGL_BAD_MATCH, "eglBindTexImage"); + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) { + _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); + return EGL_FALSE; + } + + surface->BoundToTexture = EGL_TRUE; + + return EGL_TRUE; } EGLBoolean -_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface, EGLint buffer) +_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surf, + EGLint buffer) { - /* XXX unfinished */ - return EGL_FALSE; + /* Just do basic error checking and return success/fail. + * Drivers must implement the real stuff. + */ + _EGLSurface *surface = _eglLookupSurface(surf); + + if (!surface || surface->Type != EGL_PBUFFER_BIT) { + _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); + return EGL_FALSE; + } + + if (surface->TextureFormat == EGL_NO_TEXTURE) { + _eglError(EGL_BAD_MATCH, "eglBindTexImage"); + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) { + _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); + return EGL_FALSE; + } + + if (!surface->BoundToTexture) { + _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); + return EGL_FALSE; + } + + surface->BoundToTexture = EGL_FALSE; + + return EGL_TRUE; } diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h index 79abeca0b2..50f965b5cb 100644 --- a/src/egl/main/eglsurface.h +++ b/src/egl/main/eglsurface.h @@ -16,6 +16,7 @@ struct _egl_surface /* May need reference counting here */ EGLBoolean IsBound; EGLBoolean DeletePending; + EGLBoolean BoundToTexture; EGLint Type; /* one of EGL_WINDOW_BIT, EGL_PIXMAP_BIT or EGL_PBUFFER_BIT */ EGLint Width, Height; @@ -51,6 +52,10 @@ extern void _eglRemoveSurface(_EGLSurface *surf); +extern EGLSurface +_eglGetSurfaceHandle(_EGLSurface *surface); + + extern _EGLSurface * _eglLookupSurface(EGLSurface surf); diff --git a/src/egl/main/egltypedefs.h b/src/egl/main/egltypedefs.h index fa8cb496f8..9fbc55352c 100644 --- a/src/egl/main/egltypedefs.h +++ b/src/egl/main/egltypedefs.h @@ -1,8 +1,10 @@ #ifndef EGLTYPEDEFS_INCLUDED #define EGLTYPEDEFS_INCLUDED +#define EGL_EGLEXT_PROTOTYPES -#include <GLES/egl.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> typedef struct _egl_api _EGLAPI; @@ -26,9 +28,7 @@ typedef struct _egl_surface _EGLSurface; typedef struct _egl_thread_info _EGLThreadInfo; -typedef void (*_EGLProc)(); - -typedef _EGLDriver *(*_EGLMain_t)(_EGLDisplay *dpy); +typedef _EGLDriver *(*_EGLMain_t)(_EGLDisplay *dpy, const char *args); #endif /* EGLTYPEDEFS_INCLUDED */ diff --git a/src/egl/main/eglx.c b/src/egl/main/eglx.c new file mode 100644 index 0000000000..50acc3a24f --- /dev/null +++ b/src/egl/main/eglx.c @@ -0,0 +1,100 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/** + * X-specific EGL code. + * + * Any glue code needed to make EGL work with X is placed in this file. + */ + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xlib.h> + +#include "egldriver.h" +#include "egllog.h" +#include "eglstring.h" +#include "eglx.h" + + +static const char *DefaultGLXDriver = "egl_glx"; +static const char *DefaultSoftDriver = "egl_softpipe"; + + +/** + * Given an X Display ptr (at dpy->Xdpy) try to determine the appropriate + * device driver. Return its name. + * + * This boils down to whether to use the egl_glx.so driver which will + * load a DRI driver or the egl_softpipe.so driver that'll do software + * rendering on Xlib. + */ +const char * +_xeglChooseDriver(_EGLDisplay *dpy) +{ +#ifdef _EGL_PLATFORM_X + _XPrivDisplay xdpy; + int screen; + const char *driverName; + + assert(dpy); + + if (!dpy->Xdpy) { + dpy->Xdpy = XOpenDisplay(NULL); + if (!dpy->Xdpy) { + /* can't open X display -> can't use X-based driver */ + return NULL; + } + } + xdpy = (_XPrivDisplay) dpy->Xdpy; + + assert(dpy->Xdpy); + + screen = DefaultScreen(dpy->Xdpy); + + /* See if we can choose a DRI/DRM driver */ + driverName = _eglChooseDRMDriver(screen); + if (driverName) { + free((void *) driverName); + driverName = _eglstrdup(DefaultGLXDriver); + } + else { + driverName = _eglstrdup(DefaultSoftDriver); + } + + _eglLog(_EGL_DEBUG, "_xeglChooseDriver: %s", driverName); + + return driverName; +#else + return NULL; +#endif +} + + diff --git a/src/egl/main/eglx.h b/src/egl/main/eglx.h new file mode 100644 index 0000000000..4323d55838 --- /dev/null +++ b/src/egl/main/eglx.h @@ -0,0 +1,12 @@ +#ifndef EGLX_INCLUDED +#define EGLX_INCLUDED + + +#include "egldisplay.h" + + +extern const char * +_xeglChooseDriver(_EGLDisplay *dpy); + + +#endif /* EGLX_INCLUDED */ |