summaryrefslogtreecommitdiff
path: root/src/egl/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers')
-rw-r--r--src/egl/drivers/Makefile31
-rw-r--r--src/egl/drivers/Makefile.template52
-rw-r--r--src/egl/drivers/dri/Makefile69
-rw-r--r--src/egl/drivers/dri/egldri.c1205
-rw-r--r--src/egl/drivers/dri/egldri.h116
-rw-r--r--src/egl/drivers/dri2/Makefile18
-rw-r--r--src/egl/drivers/dri2/egl_dri2.c1474
-rw-r--r--src/egl/drivers/glx/Makefile16
-rw-r--r--src/egl/drivers/glx/egl_glx.c941
9 files changed, 3922 insertions, 0 deletions
diff --git a/src/egl/drivers/Makefile b/src/egl/drivers/Makefile
new file mode 100644
index 0000000000..dde4ee2255
--- /dev/null
+++ b/src/egl/drivers/Makefile
@@ -0,0 +1,31 @@
+# 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
+
+install:
+ @ for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir ; $(MAKE) install) || 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/Makefile.template b/src/egl/drivers/Makefile.template
new file mode 100644
index 0000000000..08e82c65e9
--- /dev/null
+++ b/src/egl/drivers/Makefile.template
@@ -0,0 +1,52 @@
+# src/egl/drivers/Makefile.template
+#
+# Drivers should define
+#
+# EGL_DRIVER, the driver name
+# EGL_SOURCES, the driver sources
+# EGL_INCLUDES, the include pathes
+# EGL_CFLAGS, additional CFLAGS
+# EGL_LIBS, additional LIBS
+#
+# before including this template.
+#
+
+
+EGL_DRIVER_PATH = $(TOP)/$(LIB_DIR)/egl/$(EGL_DRIVER)
+EGL_OBJECTS = $(EGL_SOURCES:.c=.o)
+
+
+default: depend $(EGL_DRIVER_PATH)
+
+$(EGL_DRIVER_PATH): $(EGL_DRIVER)
+ @$(INSTALL) -d $(TOP)/$(LIB_DIR)/egl
+ $(INSTALL) $< $(TOP)/$(LIB_DIR)/egl
+
+$(EGL_DRIVER): $(EGL_OBJECTS) Makefile $(TOP)/src/egl/drivers/Makefile.template
+ @$(MKLIB) -o $(EGL_DRIVER) -noprefix \
+ -linker '$(CC)' -ldflags '$(LDFLAGS)' \
+ -L$(TOP)/$(LIB_DIR) $(MKLIB_OPTIONS) \
+ $(EGL_OBJECTS) $(EGL_LIBS) -l$(EGL_LIB)
+
+.c.o:
+ $(CC) -c $(EGL_INCLUDES) $(CFLAGS) $(EGL_CFLAGS) $< -o $@
+
+
+install: $(EGL_DRIVER_PATH)
+ $(INSTALL) -d $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR)
+ $(MINSTALL) $(EGL_DRIVER_PATH) $(DESTDIR)$(EGL_DRIVER_INSTALL_DIR)
+
+clean:
+ rm -f $(EGL_DRIVER)
+ rm -f $(EGL_OBJECTS)
+ rm -f depend depend.bak
+
+depend: $(EGL_SOURCES)
+ @ echo "running $(MKDEP)"
+ @ rm -f depend
+ @ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(EGL_INCLUDES) $(EGL_SOURCES) \
+ >/dev/null 2>/dev/null
+
+sinclude depend
+# DO NOT DELETE
diff --git a/src/egl/drivers/dri/Makefile b/src/egl/drivers/dri/Makefile
new file mode 100644
index 0000000000..c3aacff1cf
--- /dev/null
+++ b/src/egl/drivers/dri/Makefile
@@ -0,0 +1,69 @@
+# src/egl/drivers/dri/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+
+### Include directories
+INCLUDE_DIRS = \
+ -I. \
+ -I/usr/include \
+ $(shell pkg-config --cflags-only-I libdrm) \
+ -I$(TOP)/include \
+ -I$(TOP)/include/GL/internal \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/mesa/main \
+ -I$(TOP)/src/mesa/math \
+ -I$(TOP)/src/mesa/transform \
+ -I$(TOP)/src/mesa/shader \
+ -I$(TOP)/src/mesa/swrast \
+ -I$(TOP)/src/mesa/swrast_setup \
+ -I$(TOP)/src/egl/main \
+ -I$(TOP)/src/mesa/drivers/dri/common
+
+
+HEADERS = egldri.h
+
+SOURCES = egldri.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+DRM_LIB = `pkg-config --libs libdrm`
+
+
+.c.o:
+ $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+
+default: depend library Makefile
+
+
+# EGLdri Library
+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) $(LIBS)
+
+install:
+ $(INSTALL) -d $(DESTDIR)$(INSTALL_LIB_DIR)
+ $(MINSTALL) $(TOP)/$(LIB_DIR)/libEGLdri.so $(DESTDIR)$(INSTALL_LIB_DIR)
+
+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/dri/egldri.c b/src/egl/drivers/dri/egldri.c
new file mode 100644
index 0000000000..6a8bf89985
--- /dev/null
+++ b/src/egl/drivers/dri/egldri.c
@@ -0,0 +1,1205 @@
+/**
+ * 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.
+ *
+ * There's a lot of dependencies on fbdev and the /sys/ filesystem.
+ */
+
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "egldriver.h"
+#include "egldisplay.h"
+#include "eglcontext.h"
+#include "eglconfig.h"
+#include "eglconfigutil.h"
+#include "eglsurface.h"
+#include "eglscreen.h"
+#include "eglglobals.h"
+#include "egllog.h"
+#include "eglmode.h"
+
+#include "egldri.h"
+
+const char *sysfs = "/sys/class";
+
+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, 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;
+#if 1
+ FILE *file;
+#endif
+ DIR *dir;
+ _EGLDriver *driver = NULL;;
+
+ snprintf(path, sizeof(path), "%s/drm", sysfs);
+ if (!(dir = opendir(path))) {
+ _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], &driverName[1]) != 0)
+ continue;
+
+ 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");
+ if (!file) {
+ _eglLog(_EGL_WARNING, "Failed to open %s", path);
+ return NULL;
+ }
+ fgets(path, sizeof(path), file);
+ fclose(file);
+#else
+ strcpy(path, "r200\n");
+#endif
+ if ((length = strlen(path)) > 0)
+ path[length - 1] = '\0'; /* remove the trailing newline from sysfs */
+ strncat(path, "_dri", sizeof(path));
+
+ driver = _eglOpenDriver(dpy, path);
+
+ break;
+ }
+ closedir(dir);
+
+ return driver;
+#endif
+}
+
+
+/**
+ * Called by eglCreateContext via drv->API.CreateContext().
+ */
+static EGLContext
+_eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driContext *c, *share;
+ void *sharePriv;
+ _EGLConfig *conf;
+ __GLcontextModes visMode;
+
+ c = (driContext *) calloc(1, sizeof(*c));
+ if (!c)
+ return EGL_NO_CONTEXT;
+
+ conf = _eglLookupConfig(drv, dpy, config);
+ assert(conf);
+
+ if (!_eglInitContext(drv, &c->Base, conf, attrib_list)) {
+ free(c);
+ 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;
+ }
+ }
+ share = Lookup_driContext(share_list);
+ if (share)
+ sharePriv = share->driContext.private;
+ else
+ sharePriv = NULL;
+
+ _eglConfigToContextModesRec(conf, &visMode);
+
+ c->driContext.private = disp->driScreen.createNewContext(disp, &visMode,
+ GLX_WINDOW_BIT, sharePriv, &c->driContext);
+ if (!c->driContext.private) {
+ free(c);
+ return EGL_FALSE;
+ }
+
+ /* link to display */
+ _eglLinkContext(&c->Base, &disp->Base);
+
+ return _eglGetContextHandle(&c->Base);
+}
+
+
+static EGLBoolean
+_eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext context)
+{
+ 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, drawBuf, readBuf, &ctx->driContext);
+ }
+ else {
+ /* what's this??? */
+ /* _mesa_make_current( NULL, NULL, NULL );*/
+ }
+ return EGL_TRUE;
+}
+
+
+static EGLSurface
+_eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ driSurface *surf;
+ _EGLConfig *conf;
+
+ conf = _eglLookupConfig(drv, dpy, config);
+ assert(conf);
+
+ surf = (driSurface *) calloc(1, sizeof(*surf));
+ if (!surf) {
+ return EGL_NO_SURFACE;
+ }
+
+ if (!_eglInitSurface(drv, &surf->Base, EGL_PBUFFER_BIT,
+ conf, attrib_list)) {
+ free(surf);
+ return EGL_NO_SURFACE;
+ }
+
+ /* create software-based pbuffer */
+ {
+#if 0
+ GLcontext *ctx = NULL; /* this _should_ be OK */
+#endif
+ __GLcontextModes visMode;
+ _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
+ assert(conf); /* bad config should be caught earlier */
+ _eglConfigToContextModesRec(conf, &visMode);
+
+#if 0
+ surf->mesa_framebuffer = _mesa_create_framebuffer(&visMode);
+ _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
+ GL_TRUE, /* color bufs */
+ visMode.haveDepthBuffer,
+ visMode.haveStencilBuffer,
+ visMode.haveAccumBuffer,
+ GL_FALSE, /* alpha */
+ GL_FALSE /* aux */ );
+
+ /* set pbuffer/framebuffer size */
+ _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
+ surf->Base.Width, surf->Base.Height);
+#endif
+ }
+
+ _eglLinkSurface(&surf->Base, _eglLookupDisplay(dpy));
+
+ return surf->Base.Handle;
+}
+
+
+static EGLBoolean
+_eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driSurface *fs = Lookup_driSurface(surface);
+
+ _eglUnlinkSurface(&fs->Base);
+
+ fs->drawable.destroyDrawable(disp, fs->drawable.private);
+
+ if (!_eglIsSurfaceBound(&fs->Base))
+ free(fs);
+ return EGL_TRUE;
+}
+
+
+static EGLBoolean
+_eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
+{
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driContext *fc = Lookup_driContext(context);
+
+ _eglUnlinkContext(&fc->Base);
+
+ fc->driContext.destroyContext(disp, 0, fc->driContext.private);
+
+ if (!_eglIsContextBound(&fc->Base))
+ free(fc);
+ return EGL_TRUE;
+}
+
+
+/**
+ * Create a drawing surface which can be directly displayed on a screen.
+ */
+static EGLSurface
+_eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
+ const EGLint *attrib_list)
+{
+ _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driSurface *surface;
+ __GLcontextModes visMode;
+ __DRIid drawBuf;
+
+ surface = (driSurface *) calloc(1, sizeof(*surface));
+ if (!surface) {
+ return EGL_NO_SURFACE;
+ }
+
+ /* init base class, do error checking, etc. */
+ if (!_eglInitSurface(drv, &surface->Base, EGL_SCREEN_BIT_MESA,
+ config, attrib_list)) {
+ free(surface);
+ return EGL_NO_SURFACE;
+ }
+
+ _eglLinkSurface(&surface->Base &disp->Base);
+
+
+ /*
+ * XXX this is where we should allocate video memory for the surface!
+ */
+
+
+ /* convert EGLConfig to GLvisual */
+ _eglConfigToContextModesRec(config, &visMode);
+
+ drawBuf = (__DRIid) _eglGetSurfaceHandle(&surface->Base);
+
+ /* Create a new DRI drawable */
+ if (!disp->driScreen.createNewDrawable(disp, &visMode, drawBuf,
+ &surface->drawable, GLX_WINDOW_BIT,
+ empty_attribute_list)) {
+ _eglUnlinkSurface(&surface->Base);
+ free(surface);
+ return EGL_NO_SURFACE;
+ }
+
+ return surface->Base.Handle;
+}
+
+
+/**
+ * Set the fbdev colormap to a simple linear ramp.
+ */
+static void
+_eglDRILoadColormap(driScreen *scrn)
+{
+ char path[ NAME_MAX ];
+ char *buffer;
+ int i, fd;
+
+ /* cmap attribute uses 256 lines of 16 bytes.
+ * Allocate one extra char for the \0 added by sprintf()
+ */
+ if ( !( buffer = malloc( 256 * 16 + 1 ) ) ) {
+ _eglLog(_EGL_WARNING, "Out of memory in _eglDRILoadColormap");
+ return;
+ }
+
+ /* cmap attribute uses 256 lines of 16 bytes */
+ for ( i = 0; i < 256; i++ ) {
+ int c = (i << 8) | i; /* expand to 16-bit value */
+ sprintf(&buffer[i * 16], "%02x%c%04x%04x%04x\n", i, ' ', c, c, c);
+ }
+
+ snprintf(path, sizeof(path), "%s/graphics/%s/color_map", sysfs, scrn->fb);
+ if ( !( fd = open( path, O_RDWR ) ) ) {
+ _eglLog(_EGL_WARNING, "Unable to open %s to set colormap", path);
+ return;
+ }
+ write( fd, buffer, 256 * 16 );
+ close( fd );
+
+ free( buffer );
+}
+
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ * Called via eglShowSurfaceMESA().
+ */
+EGLBoolean
+_eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
+ EGLScreenMESA screen,
+ EGLSurface surface, EGLModeMESA m)
+{
+ driDisplay *display = Lookup_driDisplay(dpy);
+ driScreen *scrn = Lookup_driScreen(dpy, screen);
+ driSurface *surf = Lookup_driSurface(surface);
+ _EGLMode *mode = _eglLookupMode(dpy, m);
+ FILE *file;
+ char fname[NAME_MAX], buffer[1000];
+ int temp;
+
+ _eglLog(_EGL_DEBUG, "Enter _eglDRIShowScreenSurface");
+
+ /* This will check that surface, screen, and mode are valid.
+ * Also, it checks that the surface is large enough for the mode, etc.
+ */
+ if (!_eglShowScreenSurfaceMESA(drv, dpy, screen, surface, m))
+ return EGL_FALSE;
+
+ assert(surface == EGL_NO_SURFACE || surf);
+ assert(m == EGL_NO_MODE_MESA || mode);
+ assert(scrn);
+
+ /*
+ * Blank/unblank screen depending on if m == EGL_NO_MODE_MESA
+ */
+ snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
+ file = fopen(fname, "r+");
+ if (!file) {
+ _eglLog(_EGL_WARNING, "kernel patch?? chown all fb sysfs attrib to allow"
+ " write - %s\n", fname);
+ return EGL_FALSE;
+ }
+ snprintf(buffer, sizeof(buffer), "%d",
+ (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
+ fputs(buffer, file);
+ fclose(file);
+
+ if (m == EGL_NO_MODE_MESA) {
+ /* all done! */
+ return EGL_TRUE;
+ }
+
+ _eglLog(_EGL_INFO, "Setting display mode to %d x %d, %d bpp",
+ mode->Width, mode->Height, display->bpp);
+
+ /*
+ * Set the display mode
+ */
+ snprintf(fname, sizeof(fname), "%s/graphics/%s/mode", sysfs, scrn->fb);
+ file = fopen(fname, "r+");
+ if (!file) {
+ _eglLog(_EGL_WARNING, "Failed to open %s to set mode", fname);
+ return EGL_FALSE;
+ }
+ /* note: nothing happens without the \n! */
+ snprintf(buffer, sizeof(buffer), "%s\n", mode->Name);
+ fputs(buffer, file);
+ fclose(file);
+ _eglLog(_EGL_INFO, "Set mode to %s in %s", mode->Name, fname);
+
+ /*
+ * Set display bpp
+ */
+ snprintf(fname, sizeof(fname), "%s/graphics/%s/bits_per_pixel",
+ sysfs, scrn->fb);
+ file = fopen(fname, "r+");
+ if (!file) {
+ _eglLog(_EGL_WARNING, "Failed to open %s to set bpp", fname);
+ return EGL_FALSE;
+ }
+ display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
+ display->cpp = display->bpp / 8;
+ snprintf(buffer, sizeof(buffer), "%d", display->bpp);
+ fputs(buffer, file);
+ fclose(file);
+
+ /*
+ * Unblank display
+ */
+ snprintf(fname, sizeof(fname), "%s/graphics/%s/blank", sysfs, scrn->fb);
+ file = fopen(fname, "r+");
+ if (!file) {
+ _eglLog(_EGL_WARNING, "Failed to open %s", fname);
+ return EGL_FALSE;
+ }
+ snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
+ fputs(buffer, file);
+ fclose(file);
+
+ /*
+ * Set fbdev buffer virtual size to surface's size.
+ */
+ snprintf(fname, sizeof(fname), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
+ file = fopen(fname, "r+");
+ snprintf(buffer, sizeof(buffer), "%d,%d", surf->Base.Width, surf->Base.Height);
+ fputs(buffer, file);
+ rewind(file);
+ fgets(buffer, sizeof(buffer), file);
+ sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
+ fclose(file);
+
+ /*
+ * round up pitch as needed
+ */
+ temp = display->virtualWidth;
+ switch (display->bpp / 8) {
+ case 1: temp = (display->virtualWidth + 127) & ~127; break;
+ case 2: temp = (display->virtualWidth + 31) & ~31; break;
+ case 3:
+ case 4: temp = (display->virtualWidth + 15) & ~15; break;
+ default:
+ _eglLog(_EGL_WARNING, "Bad display->bpp = %d in _eglDRIShowScreenSurface");
+ }
+ display->virtualWidth = temp;
+
+ /*
+ * sanity check
+ */
+ if (surf->Base.Width < display->virtualWidth ||
+ surf->Base.Height < display->virtualHeight) {
+ /* this case _should_ have been caught at the top of this function */
+ _eglLog(_EGL_WARNING, "too small of surface in _eglDRIShowScreenSurfaceMESA "
+ "%d x %d < %d x %d",
+ surf->Base.Width,
+ surf->Base.Height,
+ display->virtualWidth,
+ display->virtualHeight);
+ /*
+ return EGL_FALSE;
+ */
+ }
+
+ /* This used to be done in the _eglDRICreateScreens routine. */
+ _eglDRILoadColormap(scrn);
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Called by eglSwapBuffers via the drv->API.SwapBuffers() pointer.
+ *
+ * If the backbuffer is on a videocard, this is extraordinarily slow!
+ */
+static EGLBoolean
+_eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+{
+ driSurface *drawable = Lookup_driSurface(draw);
+
+ /* this does error checking */
+ if (!_eglSwapBuffers(drv, dpy, draw))
+ return EGL_FALSE;
+
+ drawable->drawable.swapBuffers(NULL, drawable->drawable.private);
+
+ return EGL_TRUE;
+}
+
+
+EGLBoolean
+_eglDRIGetDisplayInfo(driDisplay *dpy)
+{
+ char path[ NAME_MAX ];
+ FILE *file;
+ int i, rc;
+ drmSetVersion sv;
+ drm_magic_t magic;
+
+ snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
+ file = fopen( path, "r" );
+ if (!file) {
+ _eglLog(_EGL_WARNING, "Unable to open %s", path);
+ return EGL_FALSE;
+ }
+ fgets( path, sizeof( path ), file );
+ sscanf( path, "%x", &dpy->chipset );
+ fclose( file );
+
+ sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor);
+ if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) {
+ _eglLog(_EGL_WARNING, "drmOpen failed.");
+ return EGL_FALSE;
+ }
+
+ /* Set the interface version, asking for 1.2 */
+ sv.drm_di_major = 1;
+ sv.drm_di_minor = 2;
+ sv.drm_dd_major = -1;
+ if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv)))
+ return EGL_FALSE;
+
+ /* self authorize */
+ if (drmGetMagic(dpy->drmFD, &magic))
+ return EGL_FALSE;
+ if (drmAuthMagic(dpy->drmFD, magic))
+ return EGL_FALSE;
+
+ /* Map framebuffer and SAREA */
+ for (i = 0; ; i++) {
+ drm_handle_t handle, offset;
+ drmSize size;
+ drmMapType type;
+ drmMapFlags flags;
+ int mtrr;
+
+ if (drmGetMap(dpy->drmFD, i, &offset, &size, &type, &flags,
+ &handle, &mtrr))
+ break;
+
+ if (type == DRM_FRAME_BUFFER) {
+ rc = drmMap( dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pFB);
+ if (rc < 0) {
+ _eglLog(_EGL_WARNING, "drmMap DRM_FAME_BUFFER failed");
+ return EGL_FALSE;
+ }
+ dpy->fbSize = size;
+ _eglLog(_EGL_INFO, "Found framebuffer size: %d", dpy->fbSize);
+ }
+ else if (type == DRM_SHM) {
+ rc = drmMap(dpy->drmFD, offset, size, (drmAddressPtr) &dpy->pSAREA);
+ if (rc < 0 ) {
+ _eglLog(_EGL_WARNING, "drmMap DRM_SHM failed.");
+ return EGL_FALSE;
+ }
+ dpy->SAREASize = SAREA_MAX;
+ _eglLog(_EGL_DEBUG, "mapped SAREA 0x%08lx to %p, size %d",
+ (unsigned long) offset, dpy->pSAREA, dpy->SAREASize );
+ }
+ }
+
+ if (!dpy->pFB) {
+ _eglLog(_EGL_WARNING, "failed to map framebuffer");
+ return EGL_FALSE;
+ }
+
+ if (!dpy->pSAREA) {
+ /* if this happens, make sure you're using the most recent DRM modules */
+ _eglLog(_EGL_WARNING, "failed to map SAREA");
+ return EGL_FALSE;
+ }
+
+ memset( dpy->pSAREA, 0, dpy->SAREASize );
+
+ return EGL_TRUE;
+}
+
+
+ /* Return the DRI per screen structure */
+static __DRIscreen *
+__eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn)
+{
+ driDisplay *disp = (driDisplay *)ndpy;
+ return &disp->driScreen;
+}
+
+
+static GLboolean
+__eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen,
+ int configID, void* context,
+ drm_context_t * hHWContext)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreen *) pDRIScreen->private;
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, hHWContext)) {
+ _eglLog(_EGL_WARNING, "drmCreateContext failed.");
+ return GL_FALSE;
+ }
+ *(void**)context = (void*) *hHWContext;
+ }
+#if 0
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+
+ pDRIScreen = __glXFindDRIScreen(dpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+
+ psp = (__DRIscreen *) pDRIScreen->private;
+
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, hHWContext)) {
+ _eglLog(_EGL_WARNING, "drmCreateContext failed.");
+ return GL_FALSE;
+ }
+ *(void**)contextID = (void*) *hHWContext;
+ }
+#endif
+ return GL_TRUE;
+}
+
+
+static GLboolean
+__eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context )
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreen *) pDRIScreen->private;
+ if (psp->fd)
+ drmDestroyContext(psp->fd, context);
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+__eglCreateDrawable(__DRInativeDisplay * ndpy, int screen,
+ __DRIid drawable, drm_drawable_t * hHWDrawable)
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreen *) pDRIScreen->private;
+ if (psp->fd) {
+ if (drmCreateDrawable(psp->fd, hHWDrawable)) {
+ _eglLog(_EGL_WARNING, "drmCreateDrawable failed.");
+ return GL_FALSE;
+ }
+ }
+ return GL_TRUE;
+}
+
+
+static GLboolean
+__eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreen *) pDRIScreen->private;
+ if (psp->fd)
+ drmDestroyDrawable(psp->fd, drawable);
+
+ return GL_TRUE;
+}
+
+static GLboolean
+__eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable,
+ unsigned int* index, unsigned int* stamp,
+ int* X, int* Y, int* W, int* H,
+ int* numClipRects, drm_clip_rect_t ** pClipRects,
+ int* backX, int* backY,
+ int* numBackClipRects, drm_clip_rect_t ** pBackClipRects )
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreen *psp;
+ driSurface *surf = Lookup_driSurface((EGLSurface) drawable);
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreen *) pDRIScreen->private;
+ *X = 0;
+ *Y = 0;
+ *W = surf->Base.Width;
+ *H = surf->Base.Height;
+
+ *backX = 0;
+ *backY = 0;
+ *numBackClipRects = 0;
+ *pBackClipRects = NULL;
+
+ *numClipRects = 1;
+ *pClipRects = malloc(sizeof(**pClipRects));
+ **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
+
+ psp->pSAREA->drawableTable[0].stamp = 1;
+ *stamp = 1;
+#if 0
+ GLXDrawable drawable = (GLXDrawable) draw;
+ drm_clip_rect_t * cliprect;
+ Display* display = (Display*)dpy;
+ __DRIcontext *pcp = (__DRIcontext *)CurrentContext->driContext.private;
+ if (drawable == 0) {
+ return GL_FALSE;
+ }
+
+ cliprect = (drm_clip_rect_t*) malloc(sizeof(drm_clip_rect_t));
+ cliprect->x1 = drawable->x;
+ cliprect->y1 = drawable->y;
+ cliprect->x2 = drawable->x + drawable->w;
+ cliprect->y2 = drawable->y + drawable->h;
+
+ /* the drawable index is by client id */
+ *index = display->clientID;
+
+ *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
+ *x = drawable->x;
+ *y = drawable->y;
+ *width = drawable->w;
+ *height = drawable->h;
+ *numClipRects = 1;
+ *pClipRects = cliprect;
+
+ *backX = drawable->x;
+ *backY = drawable->y;
+ *numBackClipRects = 0;
+ *pBackClipRects = 0;
+#endif
+ return GL_TRUE;
+}
+
+
+/**
+ * Implement \c __DRIinterfaceMethods::getProcAddress.
+ */
+static __DRIfuncPtr
+get_proc_address(const char * proc_name)
+{
+ return NULL;
+}
+
+
+/**
+ * Destroy a linked list of \c __GLcontextModes structures created by
+ * \c _gl_context_modes_create.
+ *
+ * \param modes Linked list of structures to be destroyed. All structres
+ * in the list will be freed.
+ */
+static void
+__egl_context_modes_destroy(__GLcontextModes *modes)
+{
+ while ( modes != NULL ) {
+ __GLcontextModes * const next = modes->next;
+
+ free( modes );
+ modes = next;
+ }
+}
+
+
+/**
+ * Allocate a linked list of \c __GLcontextModes structures. The fields of
+ * each structure will be initialized to "reasonable" default values. In
+ * most cases this is the default value defined by table 3.4 of the GLX
+ * 1.3 specification. This means that most values are either initialized to
+ * zero or \c GLX_DONT_CARE (which is -1). As support for additional
+ * extensions is added, the new values will be initialized to appropriate
+ * values from the extension specification.
+ *
+ * \param count Number of structures to allocate.
+ * \param minimum_size Minimum size of a structure to allocate. This allows
+ * for differences in the version of the
+ * \c __GLcontextModes stucture used in libGL and in a
+ * DRI-based driver.
+ * \returns A pointer to the first element in a linked list of \c count
+ * stuctures on success, or \c NULL on failure.
+ *
+ * \warning Use of \c minimum_size does \b not guarantee binary compatibility.
+ * The fundamental assumption is that if the \c minimum_size
+ * specified by the driver and the size of the \c __GLcontextModes
+ * structure in libGL is the same, then the meaning of each byte in
+ * the structure is the same in both places. \b Be \b careful!
+ * Basically this means that fields have to be added in libGL and
+ * then propagated to drivers. Drivers should \b never arbitrarilly
+ * extend the \c __GLcontextModes data-structure.
+ */
+static __GLcontextModes *
+__egl_context_modes_create(unsigned count, size_t minimum_size)
+{
+ const size_t size = (minimum_size > sizeof( __GLcontextModes ))
+ ? minimum_size : sizeof( __GLcontextModes );
+ __GLcontextModes * base = NULL;
+ __GLcontextModes ** next;
+ unsigned i;
+
+ next = & base;
+ for ( i = 0 ; i < count ; i++ ) {
+ *next = (__GLcontextModes *) malloc( size );
+ if ( *next == NULL ) {
+ __egl_context_modes_destroy( base );
+ base = NULL;
+ break;
+ }
+
+ (void) memset( *next, 0, size );
+ (*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 = & ((*next)->next);
+ }
+
+ return base;
+}
+
+
+static GLboolean
+__eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
+{
+ return EGL_TRUE;
+}
+
+
+/**
+ * Get the unadjusted system time (UST). Currently, the UST is measured in
+ * microseconds since Epoc. The actual resolution of the UST may vary from
+ * system to system, and the units may vary from release to release.
+ * Drivers should not call this function directly. They should instead use
+ * \c glXGetProcAddress to obtain a pointer to the function.
+ *
+ * \param ust Location to store the 64-bit UST
+ * \returns Zero on success or a negative errno value on failure.
+ *
+ * \sa glXGetProcAddress, PFNGLXGETUSTPROC
+ *
+ * \since Internal API version 20030317.
+ */
+static int
+__eglGetUST(int64_t *ust)
+{
+ struct timeval tv;
+
+ if ( ust == NULL ) {
+ return -EFAULT;
+ }
+
+ if ( gettimeofday( & tv, NULL ) == 0 ) {
+ ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
+ return 0;
+ }
+ else {
+ return -errno;
+ }
+}
+
+/**
+ * Determine the refresh rate of the specified drawable and display.
+ *
+ * \param dpy Display whose refresh rate is to be determined.
+ * \param drawable Drawable whose refresh rate is to be determined.
+ * \param numerator Numerator of the refresh rate.
+ * \param demoninator Denominator of the refresh rate.
+ * \return If the refresh rate for the specified display and drawable could
+ * be calculated, True is returned. Otherwise False is returned.
+ *
+ * \note This function is implemented entirely client-side. A lot of other
+ * functionality is required to export GLX_OML_sync_control, so on
+ * XFree86 this function can be called for direct-rendering contexts
+ * when GLX_OML_sync_control appears in the client extension string.
+ */
+static GLboolean
+__eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable,
+ int32_t * numerator, int32_t * denominator)
+{
+ return EGL_TRUE;
+}
+
+
+/**
+ * Table of functions exported by the loader to the driver.
+ */
+static const __DRIinterfaceMethods interface_methods = {
+ get_proc_address,
+
+ __egl_context_modes_create,
+ __egl_context_modes_destroy,
+
+ __eglFindDRIScreen,
+ __eglWindowExists,
+
+ __eglCreateContextWithConfig,
+ __eglDestroyContext,
+
+ __eglCreateDrawable,
+ __eglDestroyDrawable,
+ __eglGetDrawableInfo,
+
+ __eglGetUST,
+ __eglGetMSCRate,
+};
+
+
+static int
+__glXGetInternalVersion(void)
+{
+ return 20050725;
+}
+
+static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+
+
+/**
+ * Do per-display initialization.
+ */
+EGLBoolean
+_eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer)
+{
+ PFNCREATENEWSCREENFUNC createNewScreen;
+ int api_ver = __glXGetInternalVersion();
+ __DRIversion ddx_version;
+ __DRIversion dri_version;
+ __DRIversion drm_version;
+ drmVersionPtr version;
+
+ version = drmGetVersion( dpy->drmFD );
+ if ( version ) {
+ drm_version.major = version->version_major;
+ drm_version.minor = version->version_minor;
+ drm_version.patch = version->version_patchlevel;
+ drmFreeVersion( version );
+ }
+ else {
+ drm_version.major = -1;
+ drm_version.minor = -1;
+ drm_version.patch = -1;
+ }
+
+ /*
+ * Get device name (like "tdfx") and the ddx version numbers.
+ * We'll check the version in each DRI driver's "createScreen"
+ * function.
+ */
+ ddx_version.major = 4;
+ ddx_version.minor = 0;
+ ddx_version.patch = 0;
+
+ /*
+ * Get the DRI X extension version.
+ */
+ dri_version.major = 4;
+ dri_version.minor = 0;
+ dri_version.patch = 0;
+
+ createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName );
+ if ( !createNewScreen ) {
+ _eglLog(_EGL_WARNING, "Couldn't find %s function in the driver.",
+ createNewScreenName );
+ return EGL_FALSE;
+ }
+
+ dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL,
+ &ddx_version, &dri_version,
+ &drm_version, framebuffer,
+ dpy->pSAREA, dpy->drmFD,
+ api_ver,
+ & interface_methods,
+ NULL);
+ 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 );
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Create all the EGL screens for the given display.
+ */
+EGLBoolean
+_eglDRICreateScreens(driDisplay *dpy)
+{
+ const int numScreens = 1; /* XXX fix this someday */
+ int i;
+
+ for (i = 0; i < numScreens; i++) {
+ char path[ NAME_MAX ];
+ FILE *file;
+ driScreen *s;
+
+ /* Create a screen */
+ if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
+ return EGL_FALSE;
+
+ snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
+ _eglInitScreen( &s->Base );
+
+ _eglAddScreen( &dpy->Base, &s->Base );
+
+ /* Create the screen's mode list */
+ snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
+ file = fopen( path, "r" );
+ while ( fgets( path, sizeof( path ), file ) ) {
+ unsigned int x, y, r;
+ char c;
+ path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
+ sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
+ _eglAddNewMode( &s->Base, x, y, r * 1000, path );
+ }
+ fclose( file );
+
+ /*
+ * NOTE: we used to set the colormap here, but that didn't work reliably.
+ * Some entries near the start of the table would get corrupted by later
+ * mode changes.
+ */
+ }
+
+ return EGL_TRUE;
+}
+
+
+EGLBoolean
+_eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy,
+ EGLint *major, EGLint *minor)
+{
+ _EGLDisplay *disp = _eglLookupDisplay(dpy);
+ driDisplay *display;
+ const char *driverName = (const char *) disp->NativeDisplay;
+
+ assert(disp);
+
+ /* Create new driDisplay object to replace the _EGLDisplay that was
+ * previously created.
+ */
+ display = calloc(1, sizeof(*display));
+ display->Base = *disp;
+ _eglSaveDisplay(&display->Base);
+ free(disp);
+
+ *major = 1;
+ *minor = 0;
+
+ sscanf(driverName + 1, "%d", &display->minor);
+
+ drv->Initialized = EGL_TRUE;
+ return EGL_TRUE;
+}
+
+
+static EGLBoolean
+_eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
+{
+ driDisplay *display = Lookup_driDisplay(dpy);
+ _eglCleanupDisplay(&display->Base);/*rename that function*/
+ free(display);
+ free(drv);
+ return EGL_TRUE;
+}
+
+
+/**
+ * Plug in the DRI-specific functions into the driver's dispatch table.
+ * Also, enable some EGL extensions.
+ */
+void
+_eglDRIInitDriverFallbacks(_EGLDriver *drv)
+{
+ _eglInitDriverFallbacks(drv);
+
+ drv->API.Initialize = _eglDRIInitialize;
+ drv->API.Terminate = _eglDRITerminate;
+ drv->API.CreateContext = _eglDRICreateContext;
+ drv->API.MakeCurrent = _eglDRIMakeCurrent;
+ drv->API.CreatePbufferSurface = _eglDRICreatePbufferSurface;
+ drv->API.DestroySurface = _eglDRIDestroySurface;
+ drv->API.DestroyContext = _eglDRIDestroyContext;
+ drv->API.CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
+ drv->API.ShowScreenSurfaceMESA = _eglDRIShowScreenSurfaceMESA;
+ drv->API.SwapBuffers = _eglDRISwapBuffers;
+
+ /* enable supported extensions */
+ drv->Extensions.MESA_screen_surface = EGL_TRUE;
+ drv->Extensions.MESA_copy_context = EGL_TRUE;
+}
diff --git a/src/egl/drivers/dri/egldri.h b/src/egl/drivers/dri/egldri.h
new file mode 100644
index 0000000000..54a9a4ea26
--- /dev/null
+++ b/src/egl/drivers/dri/egldri.h
@@ -0,0 +1,116 @@
+#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 "dri_util.h"
+#include "drm_sarea.h"
+
+/**
+ * dri display-specific driver class derived from _EGLDisplay
+ */
+typedef struct dri_display
+{
+ _EGLDisplay Base; /**< base class */
+ void *pFB;
+ int drmFD; /**< \brief DRM device file descriptor */
+ int minor;
+ unsigned long hFrameBuffer;
+
+ int virtualWidth;
+ int virtualHeight;
+ int fbSize;
+ int bpp;
+ int cpp;
+ int card_type;
+ int SAREASize;
+ drm_sarea_t *pSAREA;
+ unsigned int serverContext; /**< \brief DRM context only active on server */
+ unsigned long FBStart; /**< \brief physical address of the framebuffer */
+ void *driverClientMsg;
+ int driverClientMsgSize;
+ unsigned chipset;
+ void *driverPrivate;
+ drm_magic_t magic;
+
+ __DRIscreen driScreen;
+
+} driDisplay;
+
+
+/**
+ * dri driver-specific screen class derived from _EGLScreen
+ */
+typedef struct dri_screen
+{
+ _EGLScreen Base;
+ char fb[NAME_MAX]; /** the screen name, like "fb0" */
+} driScreen;
+
+
+/**
+ * dri driver-specific surface class derived from _EGLSurface
+ */
+typedef struct dri_surface
+{
+ _EGLSurface Base; /* base class/object */
+ __DRIdrawable drawable;
+} driSurface;
+
+
+/**
+ * dri driver-specific context class derived from _EGLContext
+ */
+typedef struct dri_context
+{
+ _EGLContext Base; /* base class/object */
+ __DRIcontext driContext; /**< \brief context dependent methods */
+} driContext;
+
+
+
+static inline driDisplay *
+Lookup_driDisplay(EGLDisplay dpy)
+{
+ _EGLDisplay *d = _eglLookupDisplay(dpy);
+ return (driDisplay *) d;
+}
+
+
+static inline driScreen *
+Lookup_driScreen(EGLDisplay dpy, EGLScreenMESA screen)
+{
+ _EGLScreen *s = _eglLookupScreen(dpy, screen);
+ return (driScreen *) s;
+}
+
+
+static inline driContext *
+Lookup_driContext(EGLContext ctx)
+{
+ _EGLContext *c = _eglLookupContext(ctx);
+ return (driContext *) c;
+}
+
+
+static inline driSurface *
+Lookup_driSurface(EGLSurface surf)
+{
+ _EGLSurface *s = _eglLookupSurface(surf);
+ return (driSurface *) s;
+}
+
+extern void _eglDRIInitDriverFallbacks(_EGLDriver *drv);
+extern EGLBoolean _eglDRIShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface surface, EGLModeMESA m);
+extern EGLBoolean _eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor);
+extern EGLBoolean _eglDRIGetDisplayInfo(driDisplay *dpy);
+extern EGLBoolean _eglDRICreateDisplay(driDisplay *dpy, __DRIframebuffer *framebuffer);
+extern EGLBoolean _eglDRICreateScreens(driDisplay *dpy);
+
+#endif /* EGLDRI_INCLUDED */
diff --git a/src/egl/drivers/dri2/Makefile b/src/egl/drivers/dri2/Makefile
new file mode 100644
index 0000000000..4e760aec4c
--- /dev/null
+++ b/src/egl/drivers/dri2/Makefile
@@ -0,0 +1,18 @@
+# src/egl/drivers/dri2/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+EGL_DRIVER = egl_dri2.so
+EGL_SOURCES = egl_dri2.c
+
+EGL_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/egl/main \
+ -I$(TOP)/src/mapi \
+ -DDEFAULT_DRIVER_DIR=\"$(DRI_DRIVER_SEARCH_DIR)\" \
+ $(EGL_DRI2_CFLAGS)
+
+EGL_LIBS = $(EGL_DRI2_LIBS)
+
+include ../Makefile.template
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
new file mode 100644
index 0000000000..aa384cb117
--- /dev/null
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -0,0 +1,1474 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * 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, sublicense,
+ * 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
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS 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.
+ *
+ * Authors:
+ * Kristian Høgsberg <krh@bitplanet.net>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <GL/gl.h>
+#include <GL/internal/dri_interface.h>
+#include <xcb/xcb.h>
+#include <xcb/dri2.h>
+#include <xcb/xfixes.h>
+#include <X11/Xlib-xcb.h>
+
+#include <glapi/glapi.h>
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglcurrent.h"
+#include "egllog.h"
+#include "eglsurface.h"
+#include "eglimage.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+struct dri2_egl_driver
+{
+ _EGLDriver base;
+
+ void (*glFlush)(void);
+};
+
+struct dri2_egl_display
+{
+ xcb_connection_t *conn;
+ int dri2_major;
+ int dri2_minor;
+ __DRIscreen *dri_screen;
+ const __DRIconfig **driver_configs;
+ void *driver;
+ __DRIcoreExtension *core;
+ __DRIdri2Extension *dri2;
+ __DRI2flushExtension *flush;
+ __DRItexBufferExtension *tex_buffer;
+ __DRIimageExtension *image;
+ int fd;
+
+ char *device_name;
+ char *driver_name;
+
+ __DRIdri2LoaderExtension loader_extension;
+ __DRIimageLookupExtension image_lookup_extension;
+ const __DRIextension *extensions[3];
+};
+
+struct dri2_egl_context
+{
+ _EGLContext base;
+ __DRIcontext *dri_context;
+};
+
+struct dri2_egl_surface
+{
+ _EGLSurface base;
+ __DRIdrawable *dri_drawable;
+ xcb_drawable_t drawable;
+ __DRIbuffer buffers[5];
+ int buffer_count;
+ xcb_xfixes_region_t region;
+ int have_fake_front;
+ int swap_interval;
+};
+
+struct dri2_egl_config
+{
+ _EGLConfig base;
+ const __DRIconfig *dri_config;
+};
+
+struct dri2_egl_image
+{
+ _EGLImage base;
+ __DRIimage *dri_image;
+};
+
+/* standard typecasts */
+_EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
+_EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
+
+EGLint dri2_to_egl_attribute_map[] = {
+ 0,
+ EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */
+ EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */
+ EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */
+ EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */
+ EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */
+ EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */
+ EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */
+ 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */
+ EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */
+ EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */
+ 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */
+ 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */
+ 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */
+ 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */
+ EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */
+ EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */
+ 0, /* __DRI_ATTRIB_RENDER_TYPE, */
+ 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */
+ 0, /* __DRI_ATTRIB_CONFORMANT */
+ 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */
+ 0, /* __DRI_ATTRIB_STEREO */
+ 0, /* __DRI_ATTRIB_AUX_BUFFERS */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */
+ 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */
+ 0, /* __DRI_ATTRIB_FLOAT_MODE */
+ 0, /* __DRI_ATTRIB_RED_MASK */
+ 0, /* __DRI_ATTRIB_GREEN_MASK */
+ 0, /* __DRI_ATTRIB_BLUE_MASK */
+ 0, /* __DRI_ATTRIB_ALPHA_MASK */
+ EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */
+ EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */
+ EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */
+ 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */
+ 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */
+ 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */
+ 0, /* __DRI_ATTRIB_SWAP_METHOD */
+ EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */
+ EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */
+ 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */
+ 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */
+ 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */
+ 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
+ EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */
+};
+
+static void
+dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
+ int depth, xcb_visualtype_t *visual)
+{
+ struct dri2_egl_config *conf;
+ struct dri2_egl_display *dri2_dpy;
+ _EGLConfig base;
+ unsigned int attrib, value, double_buffer;
+ EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
+ int i;
+
+ dri2_dpy = disp->DriverData;
+ _eglInitConfig(&base, disp, id);
+
+ i = 0;
+ while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
+ switch (attrib) {
+ case __DRI_ATTRIB_RENDER_TYPE:
+ if (value & __DRI_ATTRIB_RGBA_BIT)
+ value = EGL_RGB_BUFFER;
+ else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
+ value = EGL_LUMINANCE_BUFFER;
+ else
+ /* not valid */;
+ _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
+ break;
+
+ case __DRI_ATTRIB_CONFIG_CAVEAT:
+ if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
+ value = EGL_NON_CONFORMANT_CONFIG;
+ else if (value & __DRI_ATTRIB_SLOW_BIT)
+ value = EGL_SLOW_CONFIG;
+ else
+ value = EGL_NONE;
+ _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
+ break;
+
+ case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
+ bind_to_texture_rgb = value;
+ break;
+
+ case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
+ bind_to_texture_rgba = value;
+ break;
+
+ case __DRI_ATTRIB_DOUBLE_BUFFER:
+ double_buffer = value;
+ break;
+
+ default:
+ key = dri2_to_egl_attribute_map[attrib];
+ if (key != 0)
+ _eglSetConfigKey(&base, key, value);
+ break;
+ }
+ }
+
+ /* In EGL, double buffer or not isn't a config attribute. Pixmaps
+ * surfaces are always single buffered, pbuffer surfaces are always
+ * back buffers and windows can be either, selected by passing an
+ * attribute at window surface construction time. To support this
+ * we ignore all double buffer configs and manipulate the buffer we
+ * return in the getBuffer callback to get the behaviour we want. */
+
+ if (double_buffer)
+ return;
+
+ if (visual != NULL) {
+ if (depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE))
+ return;
+
+ _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT |
+ EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
+
+ _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_ID, visual->visual_id);
+ _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_TYPE, visual->_class);
+ } else {
+ _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
+ EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
+ }
+
+ _eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
+ _eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
+ if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0)
+ _eglSetConfigKey(&base,
+ EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
+
+ _eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, disp->ClientAPIsMask);
+ _eglSetConfigKey(&base, EGL_CONFORMANT, disp->ClientAPIsMask);
+
+ if (!_eglValidateConfig(&base, EGL_FALSE)) {
+ _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
+ return;
+ }
+
+ conf = malloc(sizeof *conf);
+ if (conf != NULL) {
+ memcpy(&conf->base, &base, sizeof base);
+ conf->dri_config = dri_config;
+ _eglAddConfig(disp, &conf->base);
+ }
+}
+
+/**
+ * Process list of buffer received from the server
+ *
+ * Processes the list of buffers received in a reply from the server to either
+ * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
+ */
+static void
+dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
+ xcb_dri2_dri2_buffer_t *buffers, unsigned count)
+{
+ struct dri2_egl_display *dri2_dpy =
+ dri2_egl_display(dri2_surf->base.Resource.Display);
+ xcb_rectangle_t rectangle;
+ int i;
+
+ dri2_surf->buffer_count = count;
+ dri2_surf->have_fake_front = 0;
+
+ /* This assumes the DRI2 buffer attachment tokens matches the
+ * __DRIbuffer tokens. */
+ for (i = 0; i < count; i++) {
+ dri2_surf->buffers[i].attachment = buffers[i].attachment;
+ dri2_surf->buffers[i].name = buffers[i].name;
+ dri2_surf->buffers[i].pitch = buffers[i].pitch;
+ dri2_surf->buffers[i].cpp = buffers[i].cpp;
+ dri2_surf->buffers[i].flags = buffers[i].flags;
+
+ /* We only use the DRI drivers single buffer configs. This
+ * means that if we try to render to a window, DRI2 will give us
+ * the fake front buffer, which we'll use as a back buffer.
+ * Note that EGL doesn't require that several clients rendering
+ * to the same window must see the same aux buffers. */
+ if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
+ dri2_surf->have_fake_front = 1;
+ }
+
+ if (dri2_surf->region != XCB_NONE)
+ xcb_xfixes_destroy_region(dri2_dpy->conn, dri2_surf->region);
+
+ rectangle.x = 0;
+ rectangle.y = 0;
+ rectangle.width = dri2_surf->base.Width;
+ rectangle.height = dri2_surf->base.Height;
+ dri2_surf->region = xcb_generate_id(dri2_dpy->conn);
+ xcb_xfixes_create_region(dri2_dpy->conn, dri2_surf->region, 1, &rectangle);
+}
+
+static __DRIbuffer *
+dri2_get_buffers(__DRIdrawable * driDrawable,
+ int *width, int *height,
+ unsigned int *attachments, int count,
+ int *out_count, void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy =
+ dri2_egl_display(dri2_surf->base.Resource.Display);
+ xcb_dri2_dri2_buffer_t *buffers;
+ xcb_dri2_get_buffers_reply_t *reply;
+ xcb_dri2_get_buffers_cookie_t cookie;
+
+ cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
+ dri2_surf->drawable,
+ count, count, attachments);
+ reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, cookie, NULL);
+ buffers = xcb_dri2_get_buffers_buffers (reply);
+ if (buffers == NULL)
+ return NULL;
+
+ *out_count = reply->count;
+ dri2_surf->base.Width = *width = reply->width;
+ dri2_surf->base.Height = *height = reply->height;
+ dri2_process_buffers(dri2_surf, buffers, *out_count);
+
+ free(reply);
+
+ return dri2_surf->buffers;
+}
+
+static void
+dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
+{
+ /* FIXME: Does EGL support front buffer rendering at all? */
+
+#if 0
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+
+ dri2WaitGL(dri2_surf);
+#endif
+}
+
+static __DRIimage *
+dri2_lookup_egl_image(__DRIcontext *context, void *image, void *data)
+{
+ struct dri2_egl_context *dri2_ctx = data;
+ _EGLDisplay *disp = dri2_ctx->base.Resource.Display;
+ struct dri2_egl_image *dri2_img;
+ _EGLImage *img;
+
+ img = _eglLookupImage(image, disp);
+ if (img == NULL) {
+ _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
+ return NULL;
+ }
+
+ dri2_img = dri2_egl_image(image);
+
+ return dri2_img->dri_image;
+}
+
+static __DRIbuffer *
+dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
+ int *width, int *height,
+ unsigned int *attachments, int count,
+ int *out_count, void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy =
+ dri2_egl_display(dri2_surf->base.Resource.Display);
+ xcb_dri2_dri2_buffer_t *buffers;
+ xcb_dri2_get_buffers_with_format_reply_t *reply;
+ xcb_dri2_get_buffers_with_format_cookie_t cookie;
+ xcb_dri2_attach_format_t *format_attachments;
+
+ format_attachments = (xcb_dri2_attach_format_t *) attachments;
+ cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
+ dri2_surf->drawable,
+ count, count,
+ format_attachments);
+
+ reply = xcb_dri2_get_buffers_with_format_reply (dri2_dpy->conn,
+ cookie, NULL);
+ if (reply == NULL)
+ return NULL;
+
+ buffers = xcb_dri2_get_buffers_with_format_buffers (reply);
+ dri2_surf->base.Width = *width = reply->width;
+ dri2_surf->base.Height = *height = reply->height;
+ *out_count = reply->count;
+ dri2_process_buffers(dri2_surf, buffers, *out_count);
+
+ free(reply);
+
+ return dri2_surf->buffers;
+}
+
+static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
+
+struct dri2_extension_match {
+ const char *name;
+ int version;
+ int offset;
+};
+
+static struct dri2_extension_match dri2_driver_extensions[] = {
+ { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
+ { __DRI_DRI2, 1, offsetof(struct dri2_egl_display, dri2) },
+ { NULL }
+};
+
+static struct dri2_extension_match dri2_core_extensions[] = {
+ { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
+ { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
+ { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
+ { NULL }
+};
+
+static EGLBoolean
+dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
+ struct dri2_extension_match *matches,
+ const __DRIextension **extensions)
+{
+ int i, j, ret = EGL_TRUE;
+ void *field;
+
+ for (i = 0; extensions[i]; i++) {
+ _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name);
+ for (j = 0; matches[j].name; j++) {
+ if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
+ extensions[i]->version >= matches[j].version) {
+ field = ((char *) dri2_dpy + matches[j].offset);
+ *(const __DRIextension **) field = extensions[i];
+ _eglLog(_EGL_INFO, "DRI2: found extension %s version %d",
+ extensions[i]->name, extensions[i]->version);
+ }
+ }
+ }
+
+ for (j = 0; matches[j].name; j++) {
+ field = ((char *) dri2_dpy + matches[j].offset);
+ if (*(const __DRIextension **) field == NULL) {
+ _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d",
+ matches[j].name, matches[j].version);
+ ret = EGL_FALSE;
+ }
+ }
+
+ return ret;
+}
+
+static char *
+dri2_strndup(const char *s, int length)
+{
+ char *d;
+
+ d = malloc(length + 1);
+ if (d == NULL)
+ return NULL;
+
+ memcpy(d, s, length);
+ d[length] = '\0';
+
+ return d;
+}
+
+static EGLBoolean
+dri2_connect(struct dri2_egl_display *dri2_dpy)
+{
+ xcb_xfixes_query_version_reply_t *xfixes_query;
+ xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
+ xcb_dri2_query_version_reply_t *dri2_query;
+ xcb_dri2_query_version_cookie_t dri2_query_cookie;
+ xcb_dri2_connect_reply_t *connect;
+ xcb_dri2_connect_cookie_t connect_cookie;
+ xcb_generic_error_t *error;
+ xcb_screen_iterator_t s;
+
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
+ xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
+
+ xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
+ XCB_XFIXES_MAJOR_VERSION,
+ XCB_XFIXES_MINOR_VERSION);
+
+ dri2_query_cookie = xcb_dri2_query_version (dri2_dpy->conn,
+ XCB_DRI2_MAJOR_VERSION,
+ XCB_DRI2_MINOR_VERSION);
+
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ connect_cookie = xcb_dri2_connect_unchecked (dri2_dpy->conn,
+ s.data->root,
+ XCB_DRI2_DRIVER_TYPE_DRI);
+
+ xfixes_query =
+ xcb_xfixes_query_version_reply (dri2_dpy->conn,
+ xfixes_query_cookie, &error);
+ if (xfixes_query == NULL ||
+ error != NULL || xfixes_query->major_version < 2) {
+ _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version");
+ free(error);
+ return EGL_FALSE;
+ }
+ free(xfixes_query);
+
+ dri2_query =
+ xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
+ if (dri2_query == NULL || error != NULL) {
+ _eglLog(_EGL_FATAL, "DRI2: failed to query version");
+ free(error);
+ return EGL_FALSE;
+ }
+ dri2_dpy->dri2_major = dri2_query->major_version;
+ dri2_dpy->dri2_minor = dri2_query->minor_version;
+ free(dri2_query);
+
+ connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
+ if (connect == NULL ||
+ connect->driver_name_length + connect->device_name_length == 0) {
+ _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
+ return EGL_FALSE;
+ }
+
+ dri2_dpy->device_name =
+ dri2_strndup(xcb_dri2_connect_device_name (connect),
+ xcb_dri2_connect_device_name_length (connect));
+
+ dri2_dpy->driver_name =
+ dri2_strndup(xcb_dri2_connect_driver_name (connect),
+ xcb_dri2_connect_driver_name_length (connect));
+
+ if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) {
+ free(dri2_dpy->device_name);
+ free(dri2_dpy->driver_name);
+ free(connect);
+ return EGL_FALSE;
+ }
+ free(connect);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_authenticate(struct dri2_egl_display *dri2_dpy)
+{
+ xcb_dri2_authenticate_reply_t *authenticate;
+ xcb_dri2_authenticate_cookie_t authenticate_cookie;
+ xcb_screen_iterator_t s;
+ drm_magic_t magic;
+
+ if (drmGetMagic(dri2_dpy->fd, &magic)) {
+ _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
+ return EGL_FALSE;
+ }
+
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ authenticate_cookie =
+ xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, magic);
+ authenticate =
+ xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
+ if (authenticate == NULL || !authenticate->authenticated) {
+ _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
+ free(authenticate);
+ return EGL_FALSE;
+ }
+
+ free(authenticate);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
+ _EGLDisplay *disp)
+{
+ xcb_screen_iterator_t s;
+ xcb_depth_iterator_t d;
+ xcb_visualtype_t *visuals;
+ int i, j, id;
+
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ d = xcb_screen_allowed_depths_iterator(s.data);
+ id = 1;
+ while (d.rem > 0) {
+ EGLBoolean class_added[6] = { 0, };
+
+ visuals = xcb_depth_visuals(d.data);
+ for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
+ if (class_added[visuals[i]._class])
+ continue;
+
+ class_added[visuals[i]._class] = EGL_TRUE;
+ for (j = 0; dri2_dpy->driver_configs[j]; j++)
+ dri2_add_config(disp, dri2_dpy->driver_configs[j],
+ id++, d.data->depth, &visuals[i]);
+ }
+
+ xcb_depth_next(&d);
+ }
+
+ if (!disp->NumConfigs) {
+ _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
+ return EGL_FALSE;
+ }
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_load_driver(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = disp->DriverData;
+ const __DRIextension **extensions;
+ char path[PATH_MAX], *search_paths, *p, *next, *end;
+
+ search_paths = NULL;
+ if (geteuid() == getuid()) {
+ /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
+ search_paths = getenv("LIBGL_DRIVERS_PATH");
+ }
+ if (search_paths == NULL)
+ search_paths = DEFAULT_DRIVER_DIR;
+
+ dri2_dpy->driver = NULL;
+ end = search_paths + strlen(search_paths);
+ for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) {
+ int len;
+ next = strchr(p, ':');
+ if (next == NULL)
+ next = end;
+
+ len = next - p;
+#if GLX_USE_TLS
+ snprintf(path, sizeof path,
+ "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name);
+ dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+#endif
+ if (dri2_dpy->driver == NULL) {
+ snprintf(path, sizeof path,
+ "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name);
+ dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
+ if (dri2_dpy->driver == NULL)
+ _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror());
+ }
+ }
+
+ if (dri2_dpy->driver == NULL) {
+ _eglLog(_EGL_WARNING,
+ "DRI2: failed to open any driver (search paths %s)",
+ search_paths);
+ return EGL_FALSE;
+ }
+
+ _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
+ extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
+ if (extensions == NULL) {
+ _eglLog(_EGL_WARNING,
+ "DRI2: driver exports no extensions (%s)", dlerror());
+ dlclose(dri2_dpy->driver);
+ return EGL_FALSE;
+ }
+
+ if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) {
+ dlclose(dri2_dpy->driver);
+ return EGL_FALSE;
+ }
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglInitialize(), GLX_drv->API.Initialize().
+ */
+static EGLBoolean
+dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
+ EGLint *major, EGLint *minor)
+{
+ const __DRIextension **extensions;
+ struct dri2_egl_display *dri2_dpy;
+ unsigned int api_mask;
+
+ dri2_dpy = malloc(sizeof *dri2_dpy);
+ if (!dri2_dpy)
+ return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+ disp->DriverData = (void *) dri2_dpy;
+ if (disp->NativeDisplay == NULL) {
+ dri2_dpy->conn = xcb_connect(0, 0);
+ } else {
+ dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
+ }
+
+ if (xcb_connection_has_error(dri2_dpy->conn)) {
+ _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
+ goto cleanup_dpy;
+ }
+
+ if (dri2_dpy->conn) {
+ if (!dri2_connect(dri2_dpy))
+ goto cleanup_conn;
+ }
+
+ if (!dri2_load_driver(disp))
+ goto cleanup_conn;
+
+ dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
+ if (dri2_dpy->fd == -1) {
+ _eglLog(_EGL_WARNING,
+ "DRI2: could not open %s (%s)", dri2_dpy->device_name,
+ strerror(errno));
+ goto cleanup_driver;
+ }
+
+ if (dri2_dpy->conn) {
+ if (!dri2_authenticate(dri2_dpy))
+ goto cleanup_fd;
+ }
+
+ if (dri2_dpy->dri2_minor >= 1) {
+ dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
+ dri2_dpy->loader_extension.base.version = 3;
+ dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
+ dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
+ dri2_dpy->loader_extension.getBuffersWithFormat =
+ dri2_get_buffers_with_format;
+ } else {
+ dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
+ dri2_dpy->loader_extension.base.version = 2;
+ dri2_dpy->loader_extension.getBuffers = dri2_get_buffers;
+ dri2_dpy->loader_extension.flushFrontBuffer = dri2_flush_front_buffer;
+ dri2_dpy->loader_extension.getBuffersWithFormat = NULL;
+ }
+
+ dri2_dpy->image_lookup_extension.base.name = __DRI_IMAGE_LOOKUP;
+ dri2_dpy->image_lookup_extension.base.version = 1;
+ dri2_dpy->image_lookup_extension.lookupEGLImage = dri2_lookup_egl_image;
+
+ dri2_dpy->extensions[0] = &dri2_dpy->loader_extension.base;
+ dri2_dpy->extensions[1] = &dri2_dpy->image_lookup_extension.base;
+ dri2_dpy->extensions[2] = NULL;
+
+ dri2_dpy->dri_screen =
+ dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
+ &dri2_dpy->driver_configs, dri2_dpy);
+
+ if (dri2_dpy->dri_screen == NULL) {
+ _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
+ goto cleanup_fd;
+ }
+
+ extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
+ if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
+ goto cleanup_dri_screen;
+
+ if (dri2_dpy->dri2->base.version >= 2)
+ api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
+ else
+ api_mask = __DRI_API_OPENGL;
+
+ disp->ClientAPIsMask = 0;
+ if (api_mask & (1 <<__DRI_API_OPENGL))
+ disp->ClientAPIsMask |= EGL_OPENGL_BIT;
+ if (api_mask & (1 <<__DRI_API_GLES))
+ disp->ClientAPIsMask |= EGL_OPENGL_ES_BIT;
+ if (api_mask & (1 << __DRI_API_GLES2))
+ disp->ClientAPIsMask |= EGL_OPENGL_ES2_BIT;
+
+ if (dri2_dpy->conn) {
+ if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
+ goto cleanup_configs;
+ }
+
+ disp->Extensions.KHR_image_base = EGL_TRUE;
+ disp->Extensions.KHR_image_pixmap = EGL_TRUE;
+ disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
+ disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
+ disp->Extensions.NOK_swap_region = EGL_TRUE;
+ disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE;
+
+ /* we're supporting EGL 1.4 */
+ *major = 1;
+ *minor = 4;
+
+ return EGL_TRUE;
+
+ cleanup_configs:
+ _eglCleanupDisplay(disp);
+ cleanup_dri_screen:
+ dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
+ cleanup_fd:
+ close(dri2_dpy->fd);
+ cleanup_driver:
+ dlclose(dri2_dpy->driver);
+ cleanup_conn:
+ if (disp->NativeDisplay == NULL)
+ xcb_disconnect(dri2_dpy->conn);
+ cleanup_dpy:
+ free(dri2_dpy);
+
+ return EGL_FALSE;
+}
+
+/**
+ * Called via eglTerminate(), drv->API.Terminate().
+ */
+static EGLBoolean
+dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+ _eglReleaseDisplayResources(drv, disp);
+ _eglCleanupDisplay(disp);
+
+ dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
+ close(dri2_dpy->fd);
+ dlclose(dri2_dpy->driver);
+ if (disp->NativeDisplay == NULL)
+ xcb_disconnect(dri2_dpy->conn);
+ free(dri2_dpy);
+ disp->DriverData = NULL;
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglCreateContext(), drv->API.CreateContext().
+ */
+static _EGLContext *
+dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
+ _EGLContext *share_list, const EGLint *attrib_list)
+{
+ struct dri2_egl_context *dri2_ctx;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
+ struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
+ int api;
+
+ dri2_ctx = malloc(sizeof *dri2_ctx);
+ if (!dri2_ctx) {
+ _eglError(EGL_BAD_ALLOC, "eglCreateContext");
+ return NULL;
+ }
+
+ if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
+ goto cleanup;
+
+ switch (dri2_ctx->base.ClientAPI) {
+ case EGL_OPENGL_ES_API:
+ switch (dri2_ctx->base.ClientVersion) {
+ case 1:
+ api = __DRI_API_GLES;
+ break;
+ case 2:
+ api = __DRI_API_GLES2;
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
+ return NULL;
+ }
+ break;
+ case EGL_OPENGL_API:
+ api = __DRI_API_OPENGL;
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
+ return NULL;
+ }
+
+ if (dri2_dpy->dri2->base.version >= 2) {
+ dri2_ctx->dri_context =
+ dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
+ api,
+ dri2_config->dri_config,
+ dri2_ctx_shared ?
+ dri2_ctx_shared->dri_context : NULL,
+ dri2_ctx);
+ } else if (api == __DRI_API_OPENGL) {
+ dri2_ctx->dri_context =
+ dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
+ dri2_config->dri_config,
+ dri2_ctx_shared ?
+ dri2_ctx_shared->dri_context : NULL,
+ dri2_ctx);
+ } else {
+ /* fail */
+ }
+
+ if (!dri2_ctx->dri_context)
+ goto cleanup;
+
+ return &dri2_ctx->base;
+
+ cleanup:
+ free(dri2_ctx);
+ return NULL;
+}
+
+static EGLBoolean
+dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
+
+ if (_eglIsSurfaceBound(surf))
+ return EGL_TRUE;
+
+ (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
+
+ xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
+
+ if (surf->Type == EGL_PBUFFER_BIT)
+ xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
+
+ free(surf);
+
+ return EGL_TRUE;
+}
+
+/**
+ * Called via eglMakeCurrent(), drv->API.MakeCurrent().
+ */
+static EGLBoolean
+dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
+ _EGLSurface *rsurf, _EGLContext *ctx)
+{
+ struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
+ struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+ __DRIdrawable *ddraw, *rdraw;
+ __DRIcontext *cctx;
+
+ /* bind the new context and return the "orphaned" one */
+ if (!_eglBindContext(&ctx, &dsurf, &rsurf))
+ return EGL_FALSE;
+
+ /* flush before context switch */
+ if (ctx && dri2_drv->glFlush)
+ dri2_drv->glFlush();
+
+ ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
+ rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
+ cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
+
+ if ((cctx == NULL && ddraw == NULL && rdraw == NULL) ||
+ dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
+ if (dsurf && !_eglIsSurfaceLinked(dsurf))
+ dri2_destroy_surface(drv, disp, dsurf);
+ if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(dsurf))
+ dri2_destroy_surface(drv, disp, rsurf);
+ if (ctx != NULL && !_eglIsContextLinked(ctx))
+ dri2_dpy->core->unbindContext(dri2_egl_context(ctx)->dri_context);
+
+ return EGL_TRUE;
+ } else {
+ _eglBindContext(&ctx, &dsurf, &rsurf);
+
+ return EGL_FALSE;
+ }
+}
+
+/**
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ */
+static _EGLSurface *
+dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
+ _EGLConfig *conf, EGLNativeWindowType window,
+ const EGLint *attrib_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
+ struct dri2_egl_surface *dri2_surf;
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+ xcb_screen_iterator_t s;
+ xcb_generic_error_t *error;
+
+ dri2_surf = malloc(sizeof *dri2_surf);
+ if (!dri2_surf) {
+ _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
+ goto cleanup_surf;
+
+ dri2_surf->region = XCB_NONE;
+ if (type == EGL_PBUFFER_BIT) {
+ dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn);
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ xcb_create_pixmap(dri2_dpy->conn,
+ _eglGetConfigKey(conf, EGL_BUFFER_SIZE),
+ dri2_surf->drawable, s.data->root,
+ dri2_surf->base.Width, dri2_surf->base.Height);
+ } else {
+ dri2_surf->drawable = window;
+ }
+
+ dri2_surf->dri_drawable =
+ (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
+ dri2_conf->dri_config, dri2_surf);
+ if (dri2_surf->dri_drawable == NULL) {
+ _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
+ goto cleanup_pixmap;
+ }
+
+ xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
+
+ if (type != EGL_PBUFFER_BIT) {
+ cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
+ reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
+ if (reply == NULL || error != NULL) {
+ _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
+ free(error);
+ goto cleanup_dri_drawable;
+ }
+
+ dri2_surf->base.Width = reply->width;
+ dri2_surf->base.Height = reply->height;
+ free(reply);
+ }
+
+ return &dri2_surf->base;
+
+ cleanup_dri_drawable:
+ dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
+ cleanup_pixmap:
+ if (type == EGL_PBUFFER_BIT)
+ xcb_free_pixmap(dri2_dpy->conn, dri2_surf->drawable);
+ cleanup_surf:
+ free(dri2_surf);
+
+ return NULL;
+}
+
+/**
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ */
+static _EGLSurface *
+dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, EGLNativeWindowType window,
+ const EGLint *attrib_list)
+{
+ return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
+ window, attrib_list);
+}
+
+static _EGLSurface *
+dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, EGLNativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ return dri2_create_surface(drv, disp, EGL_PIXMAP_BIT, conf,
+ pixmap, attrib_list);
+}
+
+static _EGLSurface *
+dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, const EGLint *attrib_list)
+{
+ return dri2_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
+ XCB_WINDOW_NONE, attrib_list);
+}
+
+static EGLBoolean
+dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLSurface *draw, xcb_xfixes_region_t region)
+{
+ struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+ _EGLContext *ctx;
+ xcb_dri2_copy_region_cookie_t cookie;
+
+ if (dri2_drv->glFlush) {
+ ctx = _eglGetCurrentContext();
+ if (ctx && ctx->DrawSurface == &dri2_surf->base)
+ dri2_drv->glFlush();
+ }
+
+ (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
+
+#if 0
+ /* FIXME: Add support for dri swapbuffers, that'll give us swap
+ * interval and page flipping (at least for fullscreen windows) as
+ * well as the page flip event. Unless surface->SwapBehavior is
+ * EGL_BUFFER_PRESERVED. */
+#if __DRI2_FLUSH_VERSION >= 2
+ if (pdraw->psc->f)
+ (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable);
+#endif
+#endif
+
+ if (!dri2_surf->have_fake_front)
+ return EGL_TRUE;
+
+ cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
+ dri2_surf->drawable,
+ region,
+ XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
+ XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT);
+ free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+{
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+
+ return dri2_copy_region(drv, disp, draw, dri2_surf->region);
+}
+
+static EGLBoolean
+dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
+ EGLint numRects, const EGLint *rects)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+ EGLBoolean ret;
+ xcb_xfixes_region_t region;
+ xcb_rectangle_t rectangles[16];
+ int i;
+
+ if (numRects > ARRAY_SIZE(rectangles))
+ return dri2_copy_region(drv, disp, draw, dri2_surf->region);
+
+ /* FIXME: Invert y here? */
+ for (i = 0; i < numRects; i++) {
+ rectangles[i].x = rects[i * 4];
+ rectangles[i].y = rects[i * 4 + 1];
+ rectangles[i].width = rects[i * 4 + 2];
+ rectangles[i].height = rects[i * 4 + 3];
+ }
+
+ region = xcb_generate_id(dri2_dpy->conn);
+ xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles);
+ ret = dri2_copy_region(drv, disp, draw, region);
+ xcb_xfixes_destroy_region(dri2_dpy->conn, region);
+
+ return ret;
+}
+
+/*
+ * Called from eglGetProcAddress() via drv->API.GetProcAddress().
+ */
+static _EGLProc
+dri2_get_proc_address(_EGLDriver *drv, const char *procname)
+{
+ /* FIXME: Do we need to support lookup of EGL symbols too? */
+
+ return (_EGLProc) _glapi_get_proc_address(procname);
+}
+
+static EGLBoolean
+dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface);
+
+ /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
+ * we need to copy fake to real here.*/
+
+ (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
+{
+ if (engine != EGL_CORE_NATIVE_ENGINE)
+ return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
+ /* glXWaitX(); */
+
+ return EGL_TRUE;
+}
+
+static void
+dri2_unload(_EGLDriver *drv)
+{
+ struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
+ free(dri2_drv);
+}
+
+static EGLBoolean
+dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
+ EGLNativePixmapType target)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
+ xcb_gcontext_t gc;
+
+ (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
+
+ gc = xcb_generate_id(dri2_dpy->conn);
+ xcb_create_gc(dri2_dpy->conn, gc, target, 0, NULL);
+ xcb_copy_area(dri2_dpy->conn,
+ dri2_surf->drawable,
+ target,
+ gc,
+ 0, 0,
+ 0, 0,
+ dri2_surf->base.Width,
+ dri2_surf->base.Height);
+ xcb_free_gc(dri2_dpy->conn, gc);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_bind_tex_image(_EGLDriver *drv,
+ _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
+ struct dri2_egl_context *dri2_ctx;
+ _EGLContext *ctx;
+ GLint format, target;
+
+ ctx = _eglGetCurrentContext();
+ dri2_ctx = dri2_egl_context(ctx);
+
+ if (!_eglBindTexImage(drv, disp, surf, buffer))
+ return EGL_FALSE;
+
+ switch (dri2_surf->base.TextureFormat) {
+ case EGL_TEXTURE_RGB:
+ format = __DRI_TEXTURE_FORMAT_RGB;
+ break;
+ case EGL_TEXTURE_RGBA:
+ format = __DRI_TEXTURE_FORMAT_RGBA;
+ break;
+ default:
+ assert(0);
+ }
+
+ switch (dri2_surf->base.TextureTarget) {
+ case EGL_TEXTURE_2D:
+ target = GL_TEXTURE_2D;
+ break;
+ default:
+ assert(0);
+ }
+
+ (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
+ target, format,
+ dri2_surf->dri_drawable);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_release_tex_image(_EGLDriver *drv,
+ _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
+{
+ return EGL_TRUE;
+}
+
+static _EGLImage *
+dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLClientBuffer buffer, const EGLint *attr_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+ struct dri2_egl_image *dri2_img;
+ unsigned int attachments[1];
+ xcb_drawable_t drawable;
+ xcb_dri2_get_buffers_cookie_t buffers_cookie;
+ xcb_dri2_get_buffers_reply_t *buffers_reply;
+ xcb_dri2_dri2_buffer_t *buffers;
+ xcb_get_geometry_cookie_t geometry_cookie;
+ xcb_get_geometry_reply_t *geometry_reply;
+ xcb_generic_error_t *error;
+ int stride, format;
+
+ drawable = (xcb_drawable_t) buffer;
+ xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
+ attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
+ buffers_cookie =
+ xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
+ drawable, 1, 1, attachments);
+ geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
+ buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
+ buffers_cookie, NULL);
+ buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
+ if (buffers == NULL) {
+ return NULL;
+ }
+
+ geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
+ geometry_cookie, &error);
+ if (geometry_reply == NULL || error != NULL) {
+ _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
+ free(error);
+ free(buffers_reply);
+ }
+
+ switch (geometry_reply->depth) {
+ case 16:
+ format = __DRI_IMAGE_FORMAT_RGB565;
+ break;
+ case 24:
+ format = __DRI_IMAGE_FORMAT_XRGB8888;
+ break;
+ case 32:
+ format = __DRI_IMAGE_FORMAT_ARGB8888;
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER,
+ "dri2_create_image_khr: unsupported pixmap depth");
+ free(buffers_reply);
+ free(geometry_reply);
+ return NULL;
+ }
+
+ dri2_img = malloc(sizeof *dri2_img);
+ if (!dri2_img) {
+ free(buffers_reply);
+ free(geometry_reply);
+ _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
+ free(buffers_reply);
+ free(geometry_reply);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ stride = buffers[0].pitch / buffers[0].cpp;
+ dri2_img->dri_image =
+ dri2_dpy->image->createImageFromName(dri2_ctx->dri_context,
+ buffers_reply->width,
+ buffers_reply->height,
+ format,
+ buffers[0].name,
+ stride,
+ dri2_img);
+
+ free(buffers_reply);
+ free(geometry_reply);
+
+ return &dri2_img->base;
+}
+
+static _EGLImage *
+dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLClientBuffer buffer,
+ const EGLint *attr_list)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+ struct dri2_egl_image *dri2_img;
+ GLuint renderbuffer = (GLuint) buffer;
+
+ if (renderbuffer == 0) {
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ dri2_img = malloc(sizeof *dri2_img);
+ if (!dri2_img) {
+ _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ if (!_eglInitImage(&dri2_img->base, disp, attr_list))
+ return EGL_NO_IMAGE_KHR;
+
+ dri2_img->dri_image =
+ dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
+ renderbuffer,
+ dri2_img);
+
+ return &dri2_img->base;
+}
+
+static _EGLImage *
+dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLContext *ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attr_list)
+{
+ switch (target) {
+ case EGL_NATIVE_PIXMAP_KHR:
+ return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
+ case EGL_GL_RENDERBUFFER_KHR:
+ return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
+ default:
+ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
+ return EGL_NO_IMAGE_KHR;
+ }
+}
+
+static EGLBoolean
+dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_image *dri2_img = dri2_egl_image(image);
+
+ dri2_dpy->image->destroyImage(dri2_img->dri_image);
+ free(dri2_img);
+
+ 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(const char *args)
+{
+ struct dri2_egl_driver *dri2_drv;
+
+ dri2_drv = malloc(sizeof *dri2_drv);
+ if (!dri2_drv)
+ return NULL;
+
+ memset(dri2_drv, 0, sizeof *dri2_drv);
+ _eglInitDriverFallbacks(&dri2_drv->base);
+ dri2_drv->base.API.Initialize = dri2_initialize;
+ dri2_drv->base.API.Terminate = dri2_terminate;
+ dri2_drv->base.API.CreateContext = dri2_create_context;
+ dri2_drv->base.API.MakeCurrent = dri2_make_current;
+ dri2_drv->base.API.CreateWindowSurface = dri2_create_window_surface;
+ dri2_drv->base.API.CreatePixmapSurface = dri2_create_pixmap_surface;
+ dri2_drv->base.API.CreatePbufferSurface = dri2_create_pbuffer_surface;
+ dri2_drv->base.API.DestroySurface = dri2_destroy_surface;
+ dri2_drv->base.API.SwapBuffers = dri2_swap_buffers;
+ dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
+ dri2_drv->base.API.WaitClient = dri2_wait_client;
+ dri2_drv->base.API.WaitNative = dri2_wait_native;
+ dri2_drv->base.API.CopyBuffers = dri2_copy_buffers;
+ dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
+ dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
+ dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr;
+ dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
+ dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region;
+
+ dri2_drv->base.Name = "DRI2";
+ dri2_drv->base.Unload = dri2_unload;
+
+ dri2_drv->glFlush =
+ (void (*)(void)) dri2_get_proc_address(&dri2_drv->base, "glFlush");
+
+ return &dri2_drv->base;
+}
diff --git a/src/egl/drivers/glx/Makefile b/src/egl/drivers/glx/Makefile
new file mode 100644
index 0000000000..d976b91a74
--- /dev/null
+++ b/src/egl/drivers/glx/Makefile
@@ -0,0 +1,16 @@
+# src/egl/drivers/glx/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+EGL_DRIVER = egl_glx.so
+EGL_SOURCES = egl_glx.c
+
+EGL_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/egl/main
+
+EGL_CFLAGS = $(X11_CFLAGS)
+EGL_LIBS = $(X11_LIBS) -lGL
+
+include ../Makefile.template
diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c
new file mode 100644
index 0000000000..e08ef5f222
--- /dev/null
+++ b/src/egl/drivers/glx/egl_glx.c
@@ -0,0 +1,941 @@
+/**************************************************************************
+ *
+ * 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>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#include "eglconfigutil.h"
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldefines.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglcurrent.h"
+#include "egllog.h"
+#include "eglsurface.h"
+
+#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
+
+#ifndef GLX_VERSION_1_4
+#error "GL/glx.h must be equal to or greater than GLX 1.4"
+#endif
+
+/** subclass of _EGLDriver */
+struct GLX_egl_driver
+{
+ _EGLDriver Base; /**< base class */
+};
+
+
+/** driver data of _EGLDisplay */
+struct GLX_egl_display
+{
+ Display *dpy;
+ XVisualInfo *visuals;
+ GLXFBConfig *fbconfigs;
+
+ int glx_maj, glx_min;
+
+ const char *extensions;
+ EGLBoolean have_1_3;
+ EGLBoolean have_make_current_read;
+ EGLBoolean have_fbconfig;
+ EGLBoolean have_pbuffer;
+
+ /* GLX_SGIX_pbuffer */
+ PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX;
+ PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX;
+
+ /* workaround quirks of different GLX implementations */
+ EGLBoolean single_buffered_quirk;
+ EGLBoolean glx_window_quirk;
+
+};
+
+
+/** subclass of _EGLContext */
+struct GLX_egl_context
+{
+ _EGLContext Base; /**< base class */
+
+ GLXContext context;
+};
+
+
+/** subclass of _EGLSurface */
+struct GLX_egl_surface
+{
+ _EGLSurface Base; /**< base class */
+
+ Drawable drawable;
+ GLXDrawable glx_drawable;
+
+ void (*destroy)(Display *, GLXDrawable);
+};
+
+
+/** subclass of _EGLConfig */
+struct GLX_egl_config
+{
+ _EGLConfig Base; /**< base class */
+ EGLBoolean double_buffered;
+ int index;
+};
+
+/* standard typecasts */
+_EGL_DRIVER_STANDARD_TYPECASTS(GLX_egl)
+
+static int
+GLX_egl_config_index(_EGLConfig *conf)
+{
+ struct GLX_egl_config *GLX_conf = GLX_egl_config(conf);
+ return GLX_conf->index;
+}
+
+
+#define MAP_ATTRIB(attr, memb) \
+ { attr, offsetof(__GLcontextModes, memb) }
+
+
+static const struct {
+ int attr;
+ int offset;
+} fbconfig_attributes[] = {
+ /* table 3.1 of GLX 1.4 */
+ MAP_ATTRIB(GLX_FBCONFIG_ID, fbconfigID),
+ MAP_ATTRIB(GLX_BUFFER_SIZE, rgbBits),
+ MAP_ATTRIB(GLX_LEVEL, level),
+ MAP_ATTRIB(GLX_DOUBLEBUFFER, doubleBufferMode),
+ MAP_ATTRIB(GLX_STEREO, stereoMode),
+ MAP_ATTRIB(GLX_AUX_BUFFERS, numAuxBuffers),
+ MAP_ATTRIB(GLX_RED_SIZE, redBits),
+ MAP_ATTRIB(GLX_GREEN_SIZE, greenBits),
+ MAP_ATTRIB(GLX_BLUE_SIZE, blueBits),
+ MAP_ATTRIB(GLX_ALPHA_SIZE, alphaBits),
+ MAP_ATTRIB(GLX_DEPTH_SIZE, depthBits),
+ MAP_ATTRIB(GLX_STENCIL_SIZE, stencilBits),
+ MAP_ATTRIB(GLX_ACCUM_RED_SIZE, accumRedBits),
+ MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE, accumGreenBits),
+ MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE, accumBlueBits),
+ MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE, accumAlphaBits),
+ MAP_ATTRIB(GLX_SAMPLE_BUFFERS, sampleBuffers),
+ MAP_ATTRIB(GLX_SAMPLES, samples),
+ MAP_ATTRIB(GLX_RENDER_TYPE, renderType),
+ MAP_ATTRIB(GLX_DRAWABLE_TYPE, drawableType),
+ MAP_ATTRIB(GLX_X_RENDERABLE, xRenderable),
+ MAP_ATTRIB(GLX_X_VISUAL_TYPE, visualType),
+ MAP_ATTRIB(GLX_CONFIG_CAVEAT, visualRating),
+ MAP_ATTRIB(GLX_TRANSPARENT_TYPE, transparentPixel),
+ MAP_ATTRIB(GLX_TRANSPARENT_INDEX_VALUE, transparentIndex),
+ MAP_ATTRIB(GLX_TRANSPARENT_RED_VALUE, transparentRed),
+ MAP_ATTRIB(GLX_TRANSPARENT_GREEN_VALUE, transparentGreen),
+ MAP_ATTRIB(GLX_TRANSPARENT_BLUE_VALUE, transparentBlue),
+ MAP_ATTRIB(GLX_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
+ MAP_ATTRIB(GLX_MAX_PBUFFER_WIDTH, maxPbufferWidth),
+ MAP_ATTRIB(GLX_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
+ MAP_ATTRIB(GLX_MAX_PBUFFER_PIXELS, maxPbufferPixels),
+ MAP_ATTRIB(GLX_VISUAL_ID, visualID),
+};
+
+
+static EGLBoolean
+convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
+ struct GLX_egl_config *GLX_conf)
+{
+ __GLcontextModes mode;
+ int err = 0, attr, val, i;
+
+ memset(&mode, 0, sizeof(mode));
+
+ for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
+ int offset = fbconfig_attributes[i].offset;
+ attr = fbconfig_attributes[i].attr;
+ err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
+ if (err) {
+ if (err == GLX_BAD_ATTRIBUTE) {
+ err = 0;
+ continue;
+ }
+ break;
+ }
+ *((int *) ((char *) &mode + offset)) = val;
+ }
+ if (err)
+ return EGL_FALSE;
+
+ /* must have rgba bit */
+ if (!(mode.renderType & GLX_RGBA_BIT))
+ return EGL_FALSE;
+
+ /* pixmap and pbuffer surfaces must be single-buffered in EGL */
+ if (mode.doubleBufferMode) {
+ mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT);
+ if (!mode.drawableType)
+ return EGL_FALSE;
+ }
+
+ mode.rgbMode = GL_TRUE;
+ mode.haveAccumBuffer = (mode.accumRedBits +
+ mode.accumGreenBits +
+ mode.accumBlueBits +
+ mode.accumAlphaBits > 0);
+ mode.haveDepthBuffer = (mode.depthBits > 0);
+ mode.haveStencilBuffer = (mode.stencilBits > 0);
+
+ GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
+ return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
+ EGL_OPENGL_BIT, EGL_OPENGL_BIT);
+}
+
+
+static const struct {
+ int attr;
+ int offset;
+} visual_attributes[] = {
+ /* table 3.7 of GLX 1.4 */
+ /* no GLX_USE_GL */
+ MAP_ATTRIB(GLX_BUFFER_SIZE, rgbBits),
+ MAP_ATTRIB(GLX_LEVEL, level),
+ MAP_ATTRIB(GLX_RGBA, rgbMode),
+ MAP_ATTRIB(GLX_DOUBLEBUFFER, doubleBufferMode),
+ MAP_ATTRIB(GLX_STEREO, stereoMode),
+ MAP_ATTRIB(GLX_AUX_BUFFERS, numAuxBuffers),
+ MAP_ATTRIB(GLX_RED_SIZE, redBits),
+ MAP_ATTRIB(GLX_GREEN_SIZE, greenBits),
+ MAP_ATTRIB(GLX_BLUE_SIZE, blueBits),
+ MAP_ATTRIB(GLX_ALPHA_SIZE, alphaBits),
+ MAP_ATTRIB(GLX_DEPTH_SIZE, depthBits),
+ MAP_ATTRIB(GLX_STENCIL_SIZE, stencilBits),
+ MAP_ATTRIB(GLX_ACCUM_RED_SIZE, accumRedBits),
+ MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE, accumGreenBits),
+ MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE, accumBlueBits),
+ MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE, accumAlphaBits),
+ MAP_ATTRIB(GLX_SAMPLE_BUFFERS, sampleBuffers),
+ MAP_ATTRIB(GLX_SAMPLES, samples),
+ MAP_ATTRIB(GLX_FBCONFIG_ID, fbconfigID),
+ /* GLX_EXT_visual_rating */
+ MAP_ATTRIB(GLX_VISUAL_CAVEAT_EXT, visualRating),
+};
+
+
+static int
+get_visual_type(const XVisualInfo *vis)
+{
+ int klass;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ klass = vis->c_class;
+#else
+ klass = vis->class;
+#endif
+
+ switch (klass) {
+ case TrueColor:
+ return GLX_TRUE_COLOR;
+ case DirectColor:
+ return GLX_DIRECT_COLOR;
+ case PseudoColor:
+ return GLX_PSEUDO_COLOR;
+ case StaticColor:
+ return GLX_STATIC_COLOR;
+ case GrayScale:
+ return GLX_GRAY_SCALE;
+ case StaticGray:
+ return GLX_STATIC_GRAY;
+ default:
+ return GLX_NONE;
+ }
+}
+
+
+static EGLBoolean
+convert_visual(Display *dpy, XVisualInfo *vinfo,
+ struct GLX_egl_config *GLX_conf)
+{
+ __GLcontextModes mode;
+ int err, attr, val, i;
+
+ /* the visual must support OpenGL */
+ err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
+ if (err || !val)
+ return EGL_FALSE;
+
+ memset(&mode, 0, sizeof(mode));
+
+ for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
+ int offset = visual_attributes[i].offset;
+ attr = visual_attributes[i].attr;
+ err = glXGetConfig(dpy, vinfo, attr, &val);
+ if (err) {
+ if (err == GLX_BAD_ATTRIBUTE) {
+ err = 0;
+ continue;
+ }
+ break;
+ }
+ *((int *) ((char *) &mode + offset)) = val;
+ }
+ if (err)
+ return EGL_FALSE;
+
+ /* must be RGB mode */
+ if (!mode.rgbMode)
+ return EGL_FALSE;
+
+ mode.visualID = vinfo->visualid;
+ mode.visualType = get_visual_type(vinfo);
+ mode.redMask = vinfo->red_mask;
+ mode.greenMask = vinfo->green_mask;
+ mode.blueMask = vinfo->blue_mask;
+
+ mode.drawableType = GLX_WINDOW_BIT;
+ /* pixmap surfaces must be single-buffered in EGL */
+ if (!mode.doubleBufferMode)
+ mode.drawableType |= GLX_PIXMAP_BIT;
+
+ mode.renderType = GLX_RGBA_BIT;
+ mode.xRenderable = GL_TRUE;
+ mode.haveAccumBuffer = (mode.accumRedBits +
+ mode.accumGreenBits +
+ mode.accumBlueBits +
+ mode.accumAlphaBits > 0);
+ mode.haveDepthBuffer = (mode.depthBits > 0);
+ mode.haveStencilBuffer = (mode.stencilBits > 0);
+
+ GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
+ return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
+ EGL_OPENGL_BIT, EGL_OPENGL_BIT);
+}
+
+
+static void
+fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
+{
+ _EGLConfig *conf = &GLX_conf->Base;
+ EGLint surface_type, r, g, b, a;
+
+ surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
+ if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
+ /* some GLX impls do not like single-buffered window surface */
+ surface_type &= ~EGL_WINDOW_BIT;
+ /* pbuffer bit is usually not set */
+ if (GLX_dpy->have_pbuffer)
+ surface_type |= EGL_PBUFFER_BIT;
+ SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
+ }
+
+ /* no visual attribs unless window bit is set */
+ if (!(surface_type & EGL_WINDOW_BIT)) {
+ SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
+ SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
+ }
+
+ /* make sure buffer size is set correctly */
+ r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
+ g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
+ b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
+ a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
+ SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
+}
+
+
+static EGLBoolean
+create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
+ EGLint screen)
+{
+ EGLint num_configs = 0, i;
+ EGLint id = 1;
+
+ if (GLX_dpy->have_fbconfig) {
+ GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
+ }
+ else {
+ XVisualInfo vinfo_template;
+ long mask;
+
+ vinfo_template.screen = screen;
+ mask = VisualScreenMask;
+ GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
+ &num_configs);
+ }
+
+ if (!num_configs)
+ return EGL_FALSE;
+
+ for (i = 0; i < num_configs; i++) {
+ struct GLX_egl_config *GLX_conf, template;
+ EGLBoolean ok;
+
+ memset(&template, 0, sizeof(template));
+ _eglInitConfig(&template.Base, dpy, id);
+ if (GLX_dpy->have_fbconfig)
+ ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template);
+ else
+ ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template);
+ if (!ok)
+ continue;
+
+ fix_config(GLX_dpy, &template);
+ if (!_eglValidateConfig(&template.Base, EGL_FALSE)) {
+ _eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i);
+ continue;
+ }
+
+ GLX_conf = CALLOC_STRUCT(GLX_egl_config);
+ if (GLX_conf) {
+ memcpy(GLX_conf, &template, sizeof(template));
+ GLX_conf->index = i;
+
+ _eglAddConfig(dpy, &GLX_conf->Base);
+ id++;
+ }
+ }
+
+ return EGL_TRUE;
+}
+
+
+static void
+check_extensions(struct GLX_egl_display *GLX_dpy, EGLint screen)
+{
+ GLX_dpy->extensions =
+ glXQueryExtensionsString(GLX_dpy->dpy, screen);
+ if (GLX_dpy->extensions) {
+ /* glXGetProcAddress is assumed */
+
+ if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) {
+ /* GLX 1.3 entry points are used */
+ GLX_dpy->have_make_current_read = EGL_TRUE;
+ }
+
+ if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) {
+ /* GLX 1.3 entry points are used */
+ GLX_dpy->have_fbconfig = EGL_TRUE;
+ }
+
+ if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) {
+ GLX_dpy->glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC)
+ glXGetProcAddress((const GLubyte *) "glXCreateGLXPbufferSGIX");
+ GLX_dpy->glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC)
+ glXGetProcAddress((const GLubyte *) "glXDestroyGLXPbufferSGIX");
+
+ if (GLX_dpy->glXCreateGLXPbufferSGIX &&
+ GLX_dpy->glXDestroyGLXPbufferSGIX &&
+ GLX_dpy->have_fbconfig)
+ GLX_dpy->have_pbuffer = EGL_TRUE;
+ }
+ }
+
+ if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) {
+ GLX_dpy->have_1_3 = EGL_TRUE;
+ GLX_dpy->have_make_current_read = EGL_TRUE;
+ GLX_dpy->have_fbconfig = EGL_TRUE;
+ GLX_dpy->have_pbuffer = EGL_TRUE;
+ }
+}
+
+
+static void
+check_quirks(struct GLX_egl_display *GLX_dpy, EGLint screen)
+{
+ const char *vendor;
+
+ GLX_dpy->single_buffered_quirk = EGL_TRUE;
+ GLX_dpy->glx_window_quirk = EGL_TRUE;
+
+ vendor = glXGetClientString(GLX_dpy->dpy, GLX_VENDOR);
+ if (vendor && strstr(vendor, "NVIDIA")) {
+ vendor = glXQueryServerString(GLX_dpy->dpy, screen, GLX_VENDOR);
+ if (vendor && strstr(vendor, "NVIDIA")) {
+ _eglLog(_EGL_DEBUG, "disable quirks");
+ GLX_dpy->single_buffered_quirk = EGL_FALSE;
+ GLX_dpy->glx_window_quirk = EGL_FALSE;
+ }
+ }
+}
+
+
+/**
+ * Called via eglInitialize(), GLX_drv->API.Initialize().
+ */
+static EGLBoolean
+GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
+ EGLint *major, EGLint *minor)
+{
+ struct GLX_egl_display *GLX_dpy;
+
+ GLX_dpy = CALLOC_STRUCT(GLX_egl_display);
+ if (!GLX_dpy)
+ return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+ GLX_dpy->dpy = (Display *) disp->NativeDisplay;
+ if (!GLX_dpy->dpy) {
+ GLX_dpy->dpy = XOpenDisplay(NULL);
+ if (!GLX_dpy->dpy) {
+ _eglLog(_EGL_WARNING, "GLX: XOpenDisplay failed");
+ free(GLX_dpy);
+ return EGL_FALSE;
+ }
+ }
+
+ if (!glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) {
+ _eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed");
+ if (!disp->NativeDisplay)
+ XCloseDisplay(GLX_dpy->dpy);
+ free(GLX_dpy);
+ return EGL_FALSE;
+ }
+
+ check_extensions(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+ check_quirks(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+
+ create_configs(disp, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+ if (!disp->NumConfigs) {
+ _eglLog(_EGL_WARNING, "GLX: failed to create any config");
+ if (!disp->NativeDisplay)
+ XCloseDisplay(GLX_dpy->dpy);
+ free(GLX_dpy);
+ return EGL_FALSE;
+ }
+
+ disp->DriverData = (void *) GLX_dpy;
+ disp->ClientAPIsMask = EGL_OPENGL_BIT;
+
+ /* we're supporting EGL 1.4 */
+ *major = 1;
+ *minor = 4;
+
+ return EGL_TRUE;
+}
+
+/**
+ * Called via eglTerminate(), drv->API.Terminate().
+ */
+static EGLBoolean
+GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+
+ _eglReleaseDisplayResources(drv, disp);
+ _eglCleanupDisplay(disp);
+
+ if (GLX_dpy->visuals)
+ XFree(GLX_dpy->visuals);
+ if (GLX_dpy->fbconfigs)
+ XFree(GLX_dpy->fbconfigs);
+
+ if (!disp->NativeDisplay)
+ XCloseDisplay(GLX_dpy->dpy);
+ free(GLX_dpy);
+
+ disp->DriverData = NULL;
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglCreateContext(), drv->API.CreateContext().
+ */
+static _EGLContext *
+GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
+ _EGLContext *share_list, const EGLint *attrib_list)
+{
+ struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_context *GLX_ctx_shared = GLX_egl_context(share_list);
+
+ if (!GLX_ctx) {
+ _eglError(EGL_BAD_ALLOC, "eglCreateContext");
+ return NULL;
+ }
+
+ if (!_eglInitContext(&GLX_ctx->Base, disp, conf, attrib_list)) {
+ free(GLX_ctx);
+ return NULL;
+ }
+
+ if (GLX_dpy->have_fbconfig)
+ GLX_ctx->context =
+ glXCreateNewContext(GLX_dpy->dpy,
+ GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+ GLX_RGBA_TYPE,
+ GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
+ GL_TRUE);
+ else
+ GLX_ctx->context =
+ glXCreateContext(GLX_dpy->dpy,
+ &GLX_dpy->visuals[GLX_egl_config_index(conf)],
+ GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
+ GL_TRUE);
+ if (!GLX_ctx->context) {
+ free(GLX_ctx);
+ return NULL;
+ }
+
+ return &GLX_ctx->Base;
+}
+
+
+/**
+ * Destroy a surface. The display is allowed to be uninitialized.
+ */
+static void
+destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
+{
+ struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
+
+ if (GLX_surf->destroy)
+ GLX_surf->destroy(disp->NativeDisplay, GLX_surf->glx_drawable);
+
+ free(GLX_surf);
+}
+
+
+/**
+ * Called via eglMakeCurrent(), drv->API.MakeCurrent().
+ */
+static EGLBoolean
+GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
+ _EGLSurface *rsurf, _EGLContext *ctx)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
+ struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
+ struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
+ GLXDrawable ddraw, rdraw;
+ GLXContext cctx;
+ EGLBoolean ret = EGL_FALSE;
+
+ /* bind the new context and return the "orphaned" one */
+ if (!_eglBindContext(&ctx, &dsurf, &rsurf))
+ return EGL_FALSE;
+
+ ddraw = (GLX_dsurf) ? GLX_dsurf->glx_drawable : None;
+ rdraw = (GLX_rsurf) ? GLX_rsurf->glx_drawable : None;
+ cctx = (GLX_ctx) ? GLX_ctx->context : NULL;
+
+ if (GLX_dpy->have_make_current_read)
+ ret = glXMakeContextCurrent(GLX_dpy->dpy, ddraw, rdraw, cctx);
+ else if (ddraw == rdraw)
+ ret = glXMakeCurrent(GLX_dpy->dpy, ddraw, cctx);
+
+ if (ret) {
+ if (dsurf && !_eglIsSurfaceLinked(dsurf))
+ destroy_surface(disp, dsurf);
+ if (rsurf && rsurf != dsurf && !_eglIsSurfaceLinked(rsurf))
+ destroy_surface(disp, rsurf);
+ }
+ else {
+ _eglBindContext(&ctx, &dsurf, &rsurf);
+ }
+
+ return ret;
+}
+
+/** 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 *disp,
+ _EGLConfig *conf, EGLNativeWindowType window,
+ const EGLint *attrib_list)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_surface *GLX_surf;
+ uint width, height;
+
+ GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+ if (!GLX_surf) {
+ _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_WINDOW_BIT,
+ conf, attrib_list)) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ GLX_surf->drawable = window;
+
+ if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk)
+ GLX_surf->glx_drawable =
+ glXCreateWindow(GLX_dpy->dpy,
+ GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+ GLX_surf->drawable, NULL);
+ else
+ GLX_surf->glx_drawable = GLX_surf->drawable;
+
+ if (!GLX_surf->glx_drawable) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk)
+ GLX_surf->destroy = glXDestroyWindow;
+
+ get_drawable_size(GLX_dpy->dpy, window, &width, &height);
+ GLX_surf->Base.Width = width;
+ GLX_surf->Base.Height = height;
+
+ return &GLX_surf->Base;
+}
+
+static _EGLSurface *
+GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, EGLNativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_surface *GLX_surf;
+ uint width, height;
+
+ GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+ if (!GLX_surf) {
+ _eglError(EGL_BAD_ALLOC, "eglCreatePixmapSurface");
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PIXMAP_BIT,
+ conf, attrib_list)) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ GLX_surf->drawable = pixmap;
+
+ if (GLX_dpy->have_1_3) {
+ GLX_surf->glx_drawable =
+ glXCreatePixmap(GLX_dpy->dpy,
+ GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+ GLX_surf->drawable, NULL);
+ }
+ else if (GLX_dpy->have_fbconfig) {
+ GLXFBConfig fbconfig = GLX_dpy->fbconfigs[GLX_egl_config_index(conf)];
+ XVisualInfo *vinfo = glXGetVisualFromFBConfig(GLX_dpy->dpy, fbconfig);
+ if (vinfo) {
+ GLX_surf->glx_drawable =
+ glXCreateGLXPixmap(GLX_dpy->dpy, vinfo, GLX_surf->drawable);
+ XFree(vinfo);
+ }
+ }
+ else {
+ GLX_surf->glx_drawable =
+ glXCreateGLXPixmap(GLX_dpy->dpy,
+ &GLX_dpy->visuals[GLX_egl_config_index(conf)],
+ GLX_surf->drawable);
+ }
+
+ if (!GLX_surf->glx_drawable) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ GLX_surf->destroy = (GLX_dpy->have_1_3) ?
+ glXDestroyPixmap : glXDestroyGLXPixmap;
+
+ get_drawable_size(GLX_dpy->dpy, pixmap, &width, &height);
+ GLX_surf->Base.Width = width;
+ GLX_surf->Base.Height = height;
+
+ return &GLX_surf->Base;
+}
+
+static _EGLSurface *
+GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp,
+ _EGLConfig *conf, const EGLint *attrib_list)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_surface *GLX_surf;
+ int attribs[5];
+ int i;
+
+ GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+ if (!GLX_surf) {
+ _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&GLX_surf->Base, disp, EGL_PBUFFER_BIT,
+ conf, attrib_list)) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ i = 0;
+ attribs[i] = None;
+
+ GLX_surf->drawable = None;
+
+ if (GLX_dpy->have_1_3) {
+ /* put geometry in attribs */
+ if (GLX_surf->Base.Width) {
+ attribs[i++] = GLX_PBUFFER_WIDTH;
+ attribs[i++] = GLX_surf->Base.Width;
+ }
+ if (GLX_surf->Base.Height) {
+ attribs[i++] = GLX_PBUFFER_HEIGHT;
+ attribs[i++] = GLX_surf->Base.Height;
+ }
+ attribs[i] = None;
+
+ GLX_surf->glx_drawable =
+ glXCreatePbuffer(GLX_dpy->dpy,
+ GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+ attribs);
+ }
+ else if (GLX_dpy->have_pbuffer) {
+ GLX_surf->glx_drawable = GLX_dpy->glXCreateGLXPbufferSGIX(
+ GLX_dpy->dpy,
+ GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+ GLX_surf->Base.Width,
+ GLX_surf->Base.Height,
+ attribs);
+ }
+
+ if (!GLX_surf->glx_drawable) {
+ free(GLX_surf);
+ return NULL;
+ }
+
+ GLX_surf->destroy = (GLX_dpy->have_1_3) ?
+ glXDestroyPbuffer : GLX_dpy->glXDestroyGLXPbufferSGIX;
+
+ return &GLX_surf->Base;
+}
+
+
+static EGLBoolean
+GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+{
+ if (!_eglIsSurfaceBound(surf))
+ destroy_surface(disp, surf);
+
+ return EGL_TRUE;
+}
+
+
+static EGLBoolean
+GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+{
+ struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+ struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw);
+
+ glXSwapBuffers(GLX_dpy->dpy, GLX_surf->glx_drawable);
+
+ return EGL_TRUE;
+}
+
+/*
+ * Called from eglGetProcAddress() via drv->API.GetProcAddress().
+ */
+static _EGLProc
+GLX_eglGetProcAddress(_EGLDriver *drv, const char *procname)
+{
+ return (_EGLProc) glXGetProcAddress((const GLubyte *) procname);
+}
+
+static EGLBoolean
+GLX_eglWaitClient(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
+{
+ glXWaitGL();
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+GLX_eglWaitNative(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
+{
+ if (engine != EGL_CORE_NATIVE_ENGINE)
+ return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
+ glXWaitX();
+ return EGL_TRUE;
+}
+
+static void
+GLX_Unload(_EGLDriver *drv)
+{
+ struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
+ free(GLX_drv);
+}
+
+
+/**
+ * This is the main entrypoint into the driver, called by libEGL.
+ * Create a new _EGLDriver object and init its dispatch table.
+ */
+_EGLDriver *
+_eglMain(const char *args)
+{
+ struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
+
+ 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.CreatePixmapSurface = GLX_eglCreatePixmapSurface;
+ GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface;
+ GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
+ GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
+ GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
+ GLX_drv->Base.API.WaitClient = GLX_eglWaitClient;
+ GLX_drv->Base.API.WaitNative = GLX_eglWaitNative;
+
+ GLX_drv->Base.Name = "GLX";
+ GLX_drv->Base.Unload = GLX_Unload;
+
+ return &GLX_drv->Base;
+}