egl: Add new EGL driver that wraps GLX.

This commit is contained in:
Alan Hourihane 2008-09-26 11:18:58 +01:00
parent d142f216d2
commit 8015f3ae3b
2 changed files with 648 additions and 0 deletions

View file

@ -0,0 +1,74 @@
# src/egl/drivers/glx/Makefile
# Build XEGL DRI driver loader library: egl_glx.so
TOP = ../../../..
include $(TOP)/configs/current
EXTRA_DEFINES = -DDEFAULT_DRIVER_DIR=\"$(DRI_DRIVER_SEARCH_DIR)\"
DRIVER_NAME = egl_glx.so
INCLUDE_DIRS = \
-I. \
-I/usr/include \
$(shell pkg-config --cflags-only-I libdrm) \
-I$(TOP)/include \
-I$(TOP)/include/GL/internal \
-I$(TOP)/src/mesa/glapi \
-I$(TOP)/src/mesa/drivers/dri/common \
-I$(TOP)/src/mesa/main \
-I$(TOP)/src/mesa \
-I$(TOP)/src/egl/main \
-I$(TOP)/src/glx/x11
SOURCES = egl_glx.c
OBJECTS = $(SOURCES:.c=.o)
DRM_LIB = `pkg-config --libs libdrm`
MISC_LIBS = -ldl -lXext -lGL
.c.o:
$(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $(EXTRA_DEFINES) $< -o $@
.PHONY: library
default: depend library Makefile
library: $(TOP)/$(LIB_DIR)/$(DRIVER_NAME)
# Make the egl_glx.so library
$(TOP)/$(LIB_DIR)/$(DRIVER_NAME): $(OBJECTS)
$(TOP)/bin/mklib -o $(DRIVER_NAME) \
-noprefix \
-major 1 -minor 0 \
-L$(TOP)/$(LIB_DIR) \
-install $(TOP)/$(LIB_DIR) \
$(OBJECTS) $(DRM_LIB) $(MISC_LIBS)
clean:
rm -f *.o
rm -f *.so
rm -f depend depend.bak
depend: $(SOURCES) $(HEADERS)
@ echo "running $(MKDEP)"
@ rm -f depend
@ touch depend
$(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \
$(SOURCES) $(HEADERS) >/dev/null 2>/dev/null
include depend
# DO NOT DELETE

View file

@ -0,0 +1,574 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* This is an EGL driver that wraps GLX. This gives the benefit of being
* completely agnostic of the direct rendering implementation.
*
* Authors: Alan Hourihane <alanh@tungstengraphics.com>
*/
/*
* TODO:
*
* Add GLXFBConfig support
* Pbuffer & Pixmap support
* test eglBind/ReleaseTexImage
*/
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "dlfcn.h"
#include <X11/Xlib.h>
#include <GL/gl.h>
#include "glxclient.h"
#define _EGL_PLATFORM_X
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "eglglobals.h"
#include "eglhash.h"
#include "egllog.h"
#include "eglsurface.h"
#include <GL/gl.h>
#define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
EGL_OPENGL_ES2_BIT |
EGL_OPENVG_BIT |
EGL_OPENGL_BIT);
struct visual_attribs
{
/* X visual attribs */
int id;
int klass;
int depth;
int redMask, greenMask, blueMask;
int colormapSize;
int bitsPerRGB;
/* GL visual attribs */
int supportsGL;
int transparentType;
int transparentRedValue;
int transparentGreenValue;
int transparentBlueValue;
int transparentAlphaValue;
int transparentIndexValue;
int bufferSize;
int level;
int render_type;
int doubleBuffer;
int stereo;
int auxBuffers;
int redSize, greenSize, blueSize, alphaSize;
int depthSize;
int stencilSize;
int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
int numSamples, numMultisample;
int visualCaveat;
};
/** subclass of _EGLDriver */
struct GLX_egl_driver
{
_EGLDriver Base; /**< base class */
XVisualInfo *visuals;
/* GLXFBConfig *fbconfigs - todo */
};
/** subclass of _EGLContext */
struct GLX_egl_context
{
_EGLContext Base; /**< base class */
GLXContext context;
};
/** subclass of _EGLSurface */
struct GLX_egl_surface
{
_EGLSurface Base; /**< base class */
GLXDrawable drawable;
};
/** subclass of _EGLConfig */
struct GLX_egl_config
{
_EGLConfig Base; /**< base class */
};
/** cast wrapper */
static struct GLX_egl_driver *
GLX_egl_driver(_EGLDriver *drv)
{
return (struct GLX_egl_driver *) drv;
}
static struct GLX_egl_context *
GLX_egl_context(_EGLContext *ctx)
{
return (struct GLX_egl_context *) ctx;
}
static struct GLX_egl_surface *
GLX_egl_surface(_EGLSurface *surf)
{
return (struct GLX_egl_surface *) surf;
}
static GLboolean
get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
struct visual_attribs *attribs)
{
const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
int rgba;
memset(attribs, 0, sizeof(struct visual_attribs));
attribs->id = vInfo->visualid;
#if defined(__cplusplus) || defined(c_plusplus)
attribs->klass = vInfo->c_class;
#else
attribs->klass = vInfo->class;
#endif
attribs->depth = vInfo->depth;
attribs->redMask = vInfo->red_mask;
attribs->greenMask = vInfo->green_mask;
attribs->blueMask = vInfo->blue_mask;
attribs->colormapSize = vInfo->colormap_size;
attribs->bitsPerRGB = vInfo->bits_per_rgb;
if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
!attribs->supportsGL)
return GL_FALSE;
glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
if (!rgba)
return GL_FALSE;
attribs->render_type = GLX_RGBA_BIT;
glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
/* get transparent pixel stuff */
glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
}
else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
}
/* multisample attribs */
#ifdef GLX_ARB_multisample
if (ext && strstr(ext, "GLX_ARB_multisample")) {
glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
}
#endif
else {
attribs->numSamples = 0;
attribs->numMultisample = 0;
}
#if defined(GLX_EXT_visual_rating)
if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
}
else {
attribs->visualCaveat = GLX_NONE_EXT;
}
#else
attribs->visualCaveat = 0;
#endif
return GL_TRUE;
}
static EGLBoolean
create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
{
XVisualInfo theTemplate;
int numVisuals;
long mask;
int i;
struct visual_attribs attribs;
/* get list of all visuals on this screen */
theTemplate.screen = DefaultScreen(disp->Xdpy);
mask = VisualScreenMask;
GLX_drv->visuals = XGetVisualInfo(disp->Xdpy, mask, &theTemplate, &numVisuals);
for (i = 0; i < numVisuals; i++) {
struct GLX_egl_config *config;
if (!get_visual_attribs(disp->Xdpy, &GLX_drv->visuals[i], &attribs))
continue;
if (attribs.doubleBuffer) {
config = CALLOC_STRUCT(GLX_egl_config);
_eglInitConfig(&config->Base, i+1);
SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE,
(EGL_WINDOW_BIT /*| EGL_PBUFFER_BIT | EGL_PIXMAP_BIT*/));
/* XXX possibly other things to init... */
_eglAddConfig(disp, &config->Base);
}
}
return EGL_TRUE;
}
/**
* Called via eglInitialize(), GLX_drv->API.Initialize().
*/
static EGLBoolean
GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
EGLint *minor, EGLint *major)
{
struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
if (!disp->Xdpy) {
disp->Xdpy = XOpenDisplay(NULL);
if (!disp->Xdpy) {
_eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
return EGL_FALSE;
}
}
GLX_drv->Base.Initialized = EGL_TRUE;
GLX_drv->Base.Name = "GLX";
/* we're supporting EGL 1.4 */
*minor = 1;
*major = 4;
create_configs(disp, GLX_drv);
return EGL_TRUE;
}
/**
* Called via eglTerminate(), drv->API.Terminate().
*/
static EGLBoolean
GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
// XCloseDisplay(disp->Xdpy);
return EGL_TRUE;
}
/**
* Called via eglCreateContext(), drv->API.CreateContext().
*/
static EGLContext
GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
EGLContext share_list, const EGLint *attrib_list)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
struct GLX_egl_context *GLX_ctx_shared = NULL;
_EGLConfig *conf;
if (!GLX_ctx)
return EGL_NO_CONTEXT;
if (!_eglInitContext(drv, dpy, &GLX_ctx->Base, config, attrib_list)) {
free(GLX_ctx);
return EGL_NO_CONTEXT;
}
if (share_list != EGL_NO_CONTEXT) {
_EGLContext *shareCtx = _eglLookupContext(share_list);
if (!shareCtx) {
_eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
return EGL_FALSE;
}
GLX_ctx_shared = GLX_egl_context(shareCtx);
}
conf = _eglLookupConfig(drv, dpy, config);
assert(conf);
GLX_ctx->context = glXCreateContext(disp->Xdpy, &GLX_drv->visuals[(int)config-1], GLX_ctx_shared ? GLX_ctx_shared->context : NULL, GL_TRUE);
if (!GLX_ctx->context)
return EGL_FALSE;
/* need to have a direct rendering context */
if (!glXIsDirect(disp->Xdpy, GLX_ctx->context))
return EGL_FALSE;
return _eglGetContextHandle(&GLX_ctx->Base);
}
/**
* Called via eglMakeCurrent(), drv->API.MakeCurrent().
*/
static EGLBoolean
GLX_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
EGLSurface r, EGLContext context)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_EGLContext *ctx = _eglLookupContext(context);
_EGLSurface *dsurf = _eglLookupSurface(d);
_EGLSurface *rsurf = _eglLookupSurface(r);
struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
if (!_eglMakeCurrent(drv, dpy, d, r, context))
return EGL_FALSE;
// if (!glXMakeContextCurrent(disp->Xdpy, GLX_dsurf->drawable, GLX_rsurf->drawable, GLX_ctx->context))
if (!glXMakeCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL))
return EGL_FALSE;
return EGL_TRUE;
}
/** Get size of given window */
static Status
get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
{
Window root;
Status stat;
int xpos, ypos;
unsigned int w, h, bw, depth;
stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
*width = w;
*height = h;
return stat;
}
/**
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
*/
static EGLSurface
GLX_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
NativeWindowType window, const EGLint *attrib_list)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
struct GLX_egl_surface *GLX_surf;
uint width, height;
GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
if (!GLX_surf)
return EGL_NO_SURFACE;
if (!_eglInitSurface(drv, dpy, &GLX_surf->Base, EGL_WINDOW_BIT,
config, attrib_list)) {
free(GLX_surf);
return EGL_FALSE;
}
_eglSaveSurface(&GLX_surf->Base);
GLX_surf->drawable = window;
get_drawable_size(disp->Xdpy, window, &width, &height);
GLX_surf->Base.Width = width;
GLX_surf->Base.Height = height;
return _eglGetSurfaceHandle(&GLX_surf->Base);
}
static EGLBoolean
GLX_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_EGLSurface *surf = _eglLookupSurface(surface);
return EGL_TRUE;
if (surf) {
_eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
if (surf->IsBound) {
surf->DeletePending = EGL_TRUE;
}
else {
free(surf);
}
return EGL_TRUE;
}
else {
_eglError(EGL_BAD_SURFACE, "eglDestroySurface");
return EGL_FALSE;
}
}
static EGLBoolean
GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
EGLint buffer)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_EGLSurface *surf = _eglLookupSurface(surface);
struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
/* buffer ?? */
glXBindTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT, NULL);
return EGL_TRUE;
}
static EGLBoolean
GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
EGLint buffer)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_EGLSurface *surf = _eglLookupSurface(surface);
struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
/* buffer ?? */
glXReleaseTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT);
return EGL_TRUE;
}
static EGLBoolean
GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
_EGLSurface *surf = _eglLookupSurface(draw);
struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
_eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers 0x%x",draw);
/* error checking step: */
if (!_eglSwapBuffers(drv, dpy, draw))
return EGL_FALSE;
glXSwapBuffers(disp->Xdpy, GLX_surf->drawable);
return EGL_TRUE;
}
/*
* Called from eglGetProcAddress() via drv->API.GetProcAddress().
*/
static _EGLProc
GLX_eglGetProcAddress(const char *procname)
{
return (_EGLProc)glXGetProcAddress((const GLubyte *)procname);
}
/**
* This is the main entrypoint into the driver, called by libEGL.
* Create a new _EGLDriver object and init its dispatch table.
*/
_EGLDriver *
_eglMain(_EGLDisplay *disp, const char *args)
{
struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
if (!GLX_drv)
return NULL;
_eglInitDriverFallbacks(&GLX_drv->Base);
GLX_drv->Base.API.Initialize = GLX_eglInitialize;
GLX_drv->Base.API.Terminate = GLX_eglTerminate;
GLX_drv->Base.API.CreateContext = GLX_eglCreateContext;
GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent;
GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface;
GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
GLX_drv->Base.API.BindTexImage = GLX_eglBindTexImage;
GLX_drv->Base.API.ReleaseTexImage = GLX_eglReleaseTexImage;
GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
GLX_drv->Base.ClientAPIsMask = all_apis;
GLX_drv->Base.Name = "GLX";
_eglLog(_EGL_DEBUG, "GLX: main(%s)", args);
/* set new DRI path to pick up EGL version (no mesa code), but don't
* override if one is already set.
*/
setenv("LIBGL_DRIVERS_PATH", DEFAULT_DRIVER_DIR"/egl", 0);
return &GLX_drv->Base;
}