Still a work in progress.
--- /dev/null
+# src/egl/drivers/dri/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+
+### Include directories
+INCLUDE_DIRS = \
+ -I. \
+ -I$(DRM_SOURCE_PATH)/shared-core \
+ -I$(DRM_SOURCE_PATH)/libdrm \
+ -I$(TOP)/include \
+ -I$(TOP)/include/GL/internal \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/mesa/main \
+ -I$(TOP)/src/mesa/glapi \
+ -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 \
+ $(DRM_SOURCE_PATH)/libdrm/xf86drm.c \
+ $(DRM_SOURCE_PATH)/libdrm/xf86drmHash.c \
+ $(DRM_SOURCE_PATH)/libdrm/xf86drmRandom.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+.c.o:
+ $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+
+default: depend library Makefile
+
+
+# EGLdri Library
+library: $(LIB_DIR)/libEGLdri.so
+
+$(LIB_DIR)/libEGLdri.so: $(OBJECTS)
+ $(TOP)/bin/mklib -o EGLdri -major 1 -minor 0 \
+ -install $(LIB_DIR) -ldl $(OBJECTS)
+
+
+clean:
+ rm -f *.o
+ rm -f *.so
+
+depend: $(SOURCES) $(HEADERS)
+ @ echo "running $(MKDEP)"
+ @ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \
+ $(SOURCES) $(HEADERS) > /dev/null
+
+include depend
+# DO NOT DELETE
+
--- /dev/null
+/*
+ * Generic EGL driver for DRI
+ */
+#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 "eglsurface.h"
+#include "eglscreen.h"
+#include "eglglobals.h"
+#include "eglmode.h"
+
+#include "egldri.h"
+
+const char *sysfs = "/sys/class";
+#define None 0
+static const int empty_attribute_list[1] = { None };
+
+/**
+ * The bootstrap function. Return a new driDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy)
+{
+ int length;
+ char path[NAME_MAX];
+ struct dirent *dirent;
+ FILE *file;
+ DIR *dir;
+ _EGLDriver *driver = NULL;;
+
+ snprintf(path, sizeof(path), "%s/drm", sysfs);
+ if (!(dir = opendir(path))) {
+ printf("EGL - %s DRM devices not found.", path);
+ return EGL_FALSE;
+ }
+ while ((dirent = readdir(dir))) {
+
+ if (strncmp(&dirent->d_name[0], "card", 4) != 0)
+ continue;
+ if (strcmp(&dirent->d_name[4], &dpy->Name[1]) != 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name", sysfs, &dpy->Name[1]);
+ file = fopen(path, "r");
+ fgets(path, sizeof(path), file);
+ fclose(file);
+
+ 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;
+}
+
+
+static EGLContext
+_eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
+{
+ _EGLConfig *conf;
+ driContext *c;
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driContext *share = Lookup_driContext(share_list);
+ void *sharePriv;
+ __GLcontextModes mode;
+ int i;
+
+ conf = _eglLookupConfig(drv, dpy, config);
+ if (!conf) {
+ _eglError(EGL_BAD_CONFIG, "eglCreateContext");
+ return EGL_NO_CONTEXT;
+ }
+
+ for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+ switch (attrib_list[i]) {
+ /* no attribs defined for now */
+ default:
+ _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
+ return EGL_NO_CONTEXT;
+ }
+ }
+
+ c = (driContext *) calloc(1, sizeof(*c));
+ if (!c)
+ return EGL_NO_CONTEXT;
+
+ _eglInitContext(&c->Base);
+ c->Base.Display = &disp->Base;
+ c->Base.Config = conf;
+ c->Base.DrawSurface = EGL_NO_SURFACE;
+ c->Base.ReadSurface = EGL_NO_SURFACE;
+
+ _eglConfigToContextModesRec(conf, &mode);
+
+ if (share)
+ sharePriv = share->driContext.private;
+ else
+ sharePriv = NULL;
+
+ c->driContext.private = disp->driScreen.createNewContext(disp, &mode,
+ GLX_WINDOW_BIT, sharePriv, &c->driContext);
+
+ if (!c->driContext.private) {
+ free(c);
+ return EGL_FALSE;
+ }
+
+ /* generate handle and insert into hash table */
+ _eglSaveContext(&c->Base);
+ assert(c->Base.Handle);
+
+ return c->Base.Handle;
+}
+
+
+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;
+
+ b = _eglMakeCurrent(drv, dpy, draw, read, context);
+ if (!b)
+ return EGL_FALSE;
+
+ if (ctx) {
+ ctx->driContext.bindContext(disp, 0, read, draw, &ctx->driContext);
+ } else {
+// _mesa_make_current( NULL, NULL, NULL );
+ }
+ return EGL_TRUE;
+}
+
+
+static EGLSurface
+_eglDRICreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
+{
+ int i;
+ for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+ switch (attrib_list[i]) {
+ /* no attribs at this time */
+ default:
+ _eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface");
+ return EGL_NO_SURFACE;
+ }
+ }
+ printf("eglCreateWindowSurface()\n");
+ /* XXX unfinished */
+
+ return EGL_NO_SURFACE;
+}
+
+
+static EGLSurface
+_eglDRICreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
+{
+ _EGLConfig *conf;
+ EGLint i;
+
+ conf = _eglLookupConfig(drv, dpy, config);
+ if (!conf) {
+ _eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface");
+ return EGL_NO_SURFACE;
+ }
+
+ for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+ switch (attrib_list[i]) {
+ /* no attribs at this time */
+ default:
+ _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
+ return EGL_NO_SURFACE;
+ }
+ }
+
+ if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) {
+ _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface");
+ return EGL_NO_SURFACE;
+ }
+
+ printf("eglCreatePixmapSurface()\n");
+ return EGL_NO_SURFACE;
+}
+
+
+static EGLSurface
+_eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
+{
+ driSurface *surf;
+
+ surf = (driSurface *) calloc(1, sizeof(*surf));
+ if (!surf) {
+ return EGL_NO_SURFACE;
+ }
+
+ if (_eglInitPbufferSurface(&surf->Base, drv, dpy, config, attrib_list) == EGL_NO_SURFACE) {
+ free(surf);
+ return EGL_NO_SURFACE;
+ }
+
+ /* create software-based pbuffer */
+ {
+// GLcontext *ctx = NULL; /* this _should_ be OK */
+ GLvisual vis;
+ _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
+ assert(conf); /* bad config should be caught earlier */
+ _eglConfigToContextModesRec(conf, &vis);
+
+#if 0
+ surf->mesa_framebuffer = _mesa_create_framebuffer(&vis);
+ _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
+ GL_TRUE, /* color bufs */
+ vis.haveDepthBuffer,
+ vis.haveStencilBuffer,
+ vis.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
+ }
+
+ return surf->Base.Handle;
+}
+
+
+static EGLBoolean
+_eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driSurface *fs = Lookup_driSurface(surface);
+ _eglRemoveSurface(&fs->Base);
+
+ fs->drawable.destroyDrawable(disp, fs->drawable.private);
+
+ if (fs->Base.IsBound) {
+ fs->Base.DeletePending = EGL_TRUE;
+ }
+ else {
+ free(fs);
+ }
+ return EGL_TRUE;
+}
+
+
+static EGLBoolean
+_eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
+{
+ driDisplay *disp = Lookup_driDisplay(dpy);
+ driContext *fc = Lookup_driContext(context);
+
+ _eglRemoveContext(&fc->Base);
+
+ fc->driContext.destroyContext(disp, 0, fc->driContext.private);
+
+ if (fc->Base.IsBound) {
+ fc->Base.DeletePending = EGL_TRUE;
+ } else {
+ 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;
+ EGLSurface surf;
+ GLvisual vis;
+
+ surface = (driSurface *) malloc(sizeof(*surface));
+ if (!surface) {
+ return EGL_NO_SURFACE;
+ }
+
+ /* init base class, error check, etc. */
+ surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list);
+ if (surf == EGL_NO_SURFACE) {
+ free(surface);
+ return EGL_NO_SURFACE;
+ }
+
+ /* convert EGLConfig to GLvisual */
+ _eglConfigToContextModesRec(config, &vis);
+
+ /* Create a new drawable */
+ if (!disp->driScreen.createNewDrawable(disp, &vis, surf, &surface->drawable,
+ GLX_WINDOW_BIT, empty_attribute_list)) {
+ free(surface);
+ _eglRemoveSurface(&surface->Base);
+ return EGL_NO_SURFACE;
+ }
+ return surf;
+}
+
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+EGLBoolean
+_eglDRIShowSurfaceMESA(_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);
+ FILE *file;
+ char buffer[NAME_MAX];
+ _EGLMode *mode = _eglLookupMode(dpy, m);
+ int width, height, temp;
+
+ _eglQuerySurface(drv, dpy, surface, EGL_WIDTH, &width);
+ _eglQuerySurface(drv, dpy, surface, EGL_HEIGHT, &height);
+
+ if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
+ return EGL_FALSE;
+
+ snprintf(buffer, sizeof(buffer), "%s/graphics/%s/blank", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file) {
+err:
+ printf("kernel patch?? chown all fb sysfs attrib to allow write - %s\n", buffer);
+ _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
+ 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)
+ return EGL_TRUE;
+
+ snprintf(buffer, sizeof(buffer), "%s/graphics/%s/mode", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file)
+ goto err;
+ fputs(mode->Name, file);
+ fclose(file);
+
+ snprintf(buffer, sizeof(buffer), "%s/graphics/%s/bits_per_pixel", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file)
+ goto err;
+ 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);
+
+ snprintf(buffer, sizeof(buffer), "%s/graphics/%s/blank", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file)
+ goto err;
+
+ snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
+ fputs(buffer, file);
+ fclose(file);
+
+ snprintf(buffer, sizeof(buffer), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
+ file = fopen(buffer, "r+");
+ snprintf(buffer, sizeof(buffer), "%d,%d", width, height);
+ fputs(buffer, file);
+ rewind(file);
+ fgets(buffer, sizeof(buffer), file);
+ sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
+ fclose(file);
+
+ 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;
+ }
+ display->virtualWidth = temp;
+
+ if ((width != display->virtualWidth) || (height != display->virtualHeight))
+ goto err;
+
+ return EGL_TRUE;
+}
+
+
+/* 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);
+
+ 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 rc, mtrr;
+ unsigned int i;
+ drmMapType type;
+ drmMapFlags flags;
+ drm_handle_t handle, offset;
+ drmSize size;
+ drmSetVersion sv;
+ drm_magic_t magic;
+
+ snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
+ file = fopen( path, "r" );
+ 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 ) {
+ fprintf( stderr, "[drm] drmOpen failed\n" );
+ 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;
+
+ for ( i = 0;; i++ ) {
+ if ( ( rc = drmGetMap( dpy->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) ) != 0 )
+ break;
+ if ( type == DRM_FRAME_BUFFER ) {
+ if ( ( rc = drmMap( dpy->drmFD, offset, size, ( drmAddressPtr ) & dpy->pFB ) ) < 0 )
+ return EGL_FALSE;
+ dpy->fbSize = size;
+ break;
+ }
+ }
+ if ( !dpy->pFB )
+ return EGL_FALSE;
+
+ dpy->SAREASize = SAREA_MAX;
+
+ for ( i = 0;; i++ ) {
+ if ( drmGetMap( dpy->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) != 0 )
+ break;
+ if ( type == DRM_SHM ) {
+ if ( drmMap( dpy->drmFD, offset, size, ( drmAddressPtr ) ( &dpy->pSAREA ) ) < 0 ) {
+ fprintf( stderr, "[drm] drmMap failed\n" );
+ return 0;
+ }
+ break;
+ }
+ }
+ if ( !dpy->pSAREA )
+ return 0;
+
+ memset( dpy->pSAREA, 0, dpy->SAREASize );
+ fprintf( stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+ offset, dpy->pSAREA, 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;
+ __DRIscreenPrivate *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreenPrivate *) pDRIScreen->private;
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, hHWContext)) {
+ fprintf(stderr, ">>> drmCreateContext failed\n");
+ return GL_FALSE;
+ }
+ *(void**)context = (void*) *hHWContext;
+ }
+#if 0
+ __DRIscreen *pDRIScreen;
+ __DRIscreenPrivate *psp;
+
+ pDRIScreen = __glXFindDRIScreen(dpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+
+ psp = (__DRIscreenPrivate *) pDRIScreen->private;
+
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, hHWContext)) {
+ fprintf(stderr, ">>> drmCreateContext failed\n");
+ return GL_FALSE;
+ }
+ *(void**)contextID = (void*) *hHWContext;
+ }
+#endif
+ return GL_TRUE;
+}
+
+static GLboolean __eglDestroyContext( __DRInativeDisplay * ndpy, int screen, __DRIid context )
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreenPrivate *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreenPrivate *) 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;
+ __DRIscreenPrivate *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreenPrivate *) pDRIScreen->private;
+ if (psp->fd) {
+ if (drmCreateDrawable(psp->fd, hHWDrawable)) {
+ fprintf(stderr, ">>> drmCreateDrawable failed\n");
+ return GL_FALSE;
+ }
+ }
+ return GL_TRUE;
+}
+
+static GLboolean __eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
+{
+ __DRIscreen *pDRIScreen;
+ __DRIscreenPrivate *psp;
+
+ pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+ if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+ return GL_FALSE;
+ }
+ psp = (__DRIscreenPrivate *) 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 )
+{
+ driSurface *surf = Lookup_driSurface(drawable);
+
+ *X = 0;
+ *Y = 0;
+ *W = surf->Base.Width;
+ *H = surf->Base.Height;
+
+ *numClipRects = 1;
+ *pClipRects = malloc(sizeof(**pClipRects));
+ **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
+
+#if 0
+ GLXDrawable drawable = (GLXDrawable) draw;
+ drm_clip_rect_t * cliprect;
+ Display* display = (Display*)dpy;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
+ if (drawable == 0) {
+ return GL_FALSE;
+ }
+
+ cliprect = (drm_clip_rect_t*) _mesa_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 )
+{
+#if 0
+ if (strcmp( proc_name, "glxEnableExtension" ) == 0) {
+ return (__DRIfuncPtr) __glXScrEnableExtension;
+ }
+#endif
+ 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.
+ */
+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.
+ */
+__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;
+}
+
+
+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.
+ */
+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.
+ */
+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,
+};
+
+
+int __glXGetInternalVersion(void)
+{
+ return 20050725;
+}
+
+static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+
+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 ) {
+ fprintf( stderr, "Couldn't find %s in CallCreateNewScreen\n", 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,
+ ( __GLcontextModes ** ) & dpy->driver_modes );
+ if (!dpy->driScreen.private)
+ return EGL_FALSE;
+
+ DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
+
+ return EGL_TRUE;
+}
+
+
+EGLBoolean
+_eglDRICreateScreen( driDisplay *dpy) {
+ char c, *buffer, path[ NAME_MAX ];
+ unsigned int i, x, y, r;
+ int fd;
+ FILE *file;
+ driScreen *s;
+ _EGLScreen *scrn;
+
+ /* Create a screen */
+ if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
+ return EGL_FALSE;
+
+ snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
+ scrn = &s->Base;
+ _eglInitScreen( scrn );
+ _eglAddScreen( &dpy->Base, scrn );
+
+ snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
+ file = fopen( path, "r" );
+ while ( fgets( path, sizeof( path ), file ) ) {
+ path[ strlen( path ) - 1 ] = '\0'; /* strip off \n from sysfs */
+ sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
+ _eglAddMode( scrn, x, y, r * 1000, path );
+ }
+ fclose( file );
+
+ /* cmap attribute uses 256 lines of 16 bytes */
+ if ( !( buffer = malloc( 256 * 16 ) ) )
+ return EGL_FALSE;
+
+ /* cmap attribute uses 256 lines of 16 bytes */
+ for ( i = 0; i < 256; i++ )
+ sprintf( &buffer[ i * 16 ], "%02x%c%4x%4x%4x\n",
+ i, ' ', 256 * i, 256 * i, 256 * i );
+
+ snprintf( path, sizeof( path ), "%s/graphics/%s/color_map", sysfs, s->fb );
+ if ( !( fd = open( path, O_RDWR ) ) )
+ return EGL_FALSE;
+ write( fd, buffer, 256 * 16 );
+ close( fd );
+
+ free( buffer );
+
+ return EGL_TRUE;
+}
+
+EGLBoolean
+_eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ _EGLDisplay *disp = _eglLookupDisplay(dpy);
+ driDisplay *display;
+
+ /* Switch display structure to one with our private fields */
+ display = calloc(1, sizeof(*display));
+ display->Base = *disp;
+ _eglHashInsert(_eglGlobal.Displays, disp->Handle, display);
+ free(disp);
+
+ *major = 1;
+ *minor = 0;
+
+ sscanf(&disp->Name[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);
+ free(display);
+ free(drv);
+ return EGL_TRUE;
+}
+
+
+void
+_eglDRIInitDriverFallbacks(_EGLDriver *drv)
+{
+ _eglInitDriverFallbacks(drv);
+
+ drv->Initialize = _eglDRIInitialize;
+ drv->Terminate = _eglDRITerminate;
+ drv->CreateContext = _eglDRICreateContext;
+ drv->MakeCurrent = _eglDRIMakeCurrent;
+ drv->CreateWindowSurface = _eglDRICreateWindowSurface;
+ drv->CreatePixmapSurface = _eglDRICreatePixmapSurface;
+ drv->CreatePbufferSurface = _eglDRICreatePbufferSurface;
+ drv->DestroySurface = _eglDRIDestroySurface;
+ drv->DestroyContext = _eglDRIDestroyContext;
+ drv->CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
+ drv->ShowSurfaceMESA = _eglDRIShowSurfaceMESA;
+ drv->SwapBuffers = _eglDRISwapBuffers;
+
+ /* enable supported extensions */
+ drv->MESA_screen_surface = EGL_TRUE;
+ drv->MESA_copy_context = EGL_TRUE;
+
+}
--- /dev/null
+/*
+ * EGL driver for radeon_dri.so
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglglobals.h"
+#include "eglmode.h"
+#include "eglscreen.h"
+#include "eglsurface.h"
+#include "egldri.h"
+
+#include "mtypes.h"
+#include "memops.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "radeon_drm.h"
+#include "radeon_dri.h"
+#include "radeon.h"
+
+static size_t radeon_drm_page_size;
+const char *sysfs = "/sys/class/graphics";
+
+/**
+ * radeon driver-specific driver class derived from _EGLDriver
+ */
+typedef struct radeon_driver
+{
+ _EGLDriver Base; /* base class/object */
+ GLuint radeonStuff;
+} radeonDriver;
+
+static int RADEONCheckDRMVersion( driDisplay *disp,
+ RADEONInfoPtr info )
+{
+ drmVersionPtr version;
+
+ version = drmGetVersion(disp->drmFD);
+ if (version) {
+ int req_minor, req_patch;
+
+ /* Need 1.8.x for proper cleanup-on-client-exit behaviour.
+ */
+ req_minor = 8;
+ req_patch = 0;
+
+ if (version->version_major != 1 ||
+ version->version_minor < req_minor ||
+ (version->version_minor == req_minor &&
+ version->version_patchlevel < req_patch)) {
+ /* Incompatible drm version */
+ fprintf(stderr,
+ "[dri] RADEONDRIScreenInit failed because of a version "
+ "mismatch.\n"
+ "[dri] radeon.o kernel module version is %d.%d.%d "
+ "but version 1.%d.%d or newer is needed.\n"
+ "[dri] Disabling DRI.\n",
+ version->version_major,
+ version->version_minor,
+ version->version_patchlevel,
+ req_minor,
+ req_patch);
+ drmFreeVersion(version);
+ return 0;
+ }
+
+ info->drmMinor = version->version_minor;
+ drmFreeVersion(version);
+ }
+
+ return 1;
+}
+
+
+/**
+ * \brief Compute base 2 logarithm.
+ *
+ * \param val value.
+ *
+ * \return base 2 logarithm of \p val.
+ */
+static int RADEONMinBits(int val)
+{
+ int bits;
+
+ if (!val) return 1;
+ for (bits = 0; val; val >>= 1, ++bits);
+ return bits;
+}
+
+
+/* Initialize the PCI GART state. Request memory for use in PCI space,
+ * and initialize the Radeon registers to point to that memory.
+ */
+static int RADEONDRIPciInit(driDisplay *disp, RADEONInfoPtr info)
+{
+ int ret;
+ int flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
+ int s, l;
+
+ ret = drmScatterGatherAlloc(disp->drmFD, info->gartSize*1024*1024,
+ &info->gartMemHandle);
+ if (ret < 0) {
+ fprintf(stderr, "[pci] Out of memory (%d)\n", ret);
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] %d kB allocated with handle 0x%04lx\n",
+ info->gartSize*1024, info->gartMemHandle);
+
+ info->gartOffset = 0;
+
+ /* Initialize the CP ring buffer data */
+ info->ringStart = info->gartOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = radeon_drm_page_size;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ /* Reserve the rest for AGP textures */
+ info->gartTexStart = info->bufStart + info->bufMapSize;
+ s = (info->gartSize*1024*1024 - info->gartTexStart);
+ l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+ info->gartTexMapSize = (s >> l) << l;
+ info->log2GARTTexGran = l;
+
+ if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] ring handle = 0x%08lx\n", info->ringHandle);
+
+ if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring read ptr mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+ DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add vertex/indirect buffers mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+ DRM_SCATTER_GATHER, 0, &info->gartTexHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add GART texture map mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] GART texture map handle = 0x%08lx\n",
+ info->gartTexHandle);
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the AGP state
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Acquires and enables the AGP device. Reserves memory in the AGP space for
+ * the ring buffer, vertex buffers and textures. Initialize the Radeon
+ * registers to point to that memory and add client mappings.
+ */
+static int RADEONDRIAgpInit( driDisplay *disp, RADEONInfoPtr info)
+{
+ int mode, ret;
+ int s, l;
+ int agpmode = 1;
+
+ if (drmAgpAcquire(disp->drmFD) < 0) {
+ fprintf(stderr, "[gart] AGP not available\n");
+ return 0;
+ }
+
+ mode = drmAgpGetMode(disp->drmFD); /* Default mode */
+ /* Disable fast write entirely - too many lockups.
+ */
+ mode &= ~RADEON_AGP_MODE_MASK;
+ switch (agpmode) {
+ case 4: mode |= RADEON_AGP_4X_MODE;
+ case 2: mode |= RADEON_AGP_2X_MODE;
+ case 1: default: mode |= RADEON_AGP_1X_MODE;
+ }
+
+ if (drmAgpEnable(disp->drmFD, mode) < 0) {
+ fprintf(stderr, "[gart] AGP not enabled\n");
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+
+#if 0
+ /* Workaround for some hardware bugs */
+ if (info->ChipFamily < CHIP_FAMILY_R200)
+ OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000);
+#endif
+ info->gartOffset = 0;
+
+ if ((ret = drmAgpAlloc(disp->drmFD, info->gartSize*1024*1024, 0, NULL,
+ &info->gartMemHandle)) < 0) {
+ fprintf(stderr, "[gart] Out of memory (%d)\n", ret);
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] %d kB allocated with handle 0x%08x\n",
+ info->gartSize*1024, (unsigned)info->gartMemHandle);
+
+ if (drmAgpBind(disp->drmFD,
+ info->gartMemHandle, info->gartOffset) < 0) {
+ fprintf(stderr, "[gart] Could not bind\n");
+ drmAgpFree(disp->drmFD, info->gartMemHandle);
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+
+ /* Initialize the CP ring buffer data */
+ info->ringStart = info->gartOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = radeon_drm_page_size;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ /* Reserve the rest for AGP textures */
+ info->gartTexStart = info->bufStart + info->bufMapSize;
+ s = (info->gartSize*1024*1024 - info->gartTexStart);
+ l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+ info->gartTexMapSize = (s >> l) << l;
+ info->log2GARTTexGran = l;
+
+ if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+ DRM_AGP, DRM_READ_ONLY, &info->ringHandle) < 0) {
+ fprintf(stderr, "[gart] Could not add ring mapping\n");
+ return 0;
+ }
+ fprintf(stderr, "[gart] ring handle = 0x%08lx\n", info->ringHandle);
+
+
+ if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_AGP, DRM_READ_ONLY, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add ring read ptr mapping\n");
+ return 0;
+ }
+
+ fprintf(stderr,
+ "[gart] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+ DRM_AGP, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add vertex/indirect buffers mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+ DRM_AGP, 0, &info->gartTexHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add AGP texture map mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] AGP texture map handle = 0x%08lx\n",
+ info->gartTexHandle);
+
+ return 1;
+}
+
+
+static int RADEONMemoryInit( driDisplay *disp, RADEONInfoPtr info )
+{
+ int width_bytes = disp->virtualWidth * disp->cpp;
+ int cpp = disp->cpp;
+ int bufferSize = ((disp->virtualHeight * width_bytes
+ + RADEON_BUFFER_ALIGN)
+ & ~RADEON_BUFFER_ALIGN);
+ int depthSize = ((((disp->virtualHeight+15) & ~15) * width_bytes
+ + RADEON_BUFFER_ALIGN)
+ & ~RADEON_BUFFER_ALIGN);
+ int l;
+
+ info->frontOffset = 0;
+ info->frontPitch = disp->virtualWidth;
+
+ fprintf(stderr,
+ "Using %d MB AGP aperture\n", info->gartSize);
+ fprintf(stderr,
+ "Using %d MB for the ring buffer\n", info->ringSize);
+ fprintf(stderr,
+ "Using %d MB for vertex/indirect buffers\n", info->bufSize);
+ fprintf(stderr,
+ "Using %d MB for AGP textures\n", info->gartTexSize);
+
+ /* Front, back and depth buffers - everything else texture??
+ */
+ info->textureSize = disp->fbSize - 2 * bufferSize - depthSize;
+
+ if (info->textureSize < 0)
+ return 0;
+
+ l = RADEONMinBits((info->textureSize-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+
+ /* Round the texture size up to the nearest whole number of
+ * texture regions. Again, be greedy about this, don't
+ * round down.
+ */
+ info->log2TexGran = l;
+ info->textureSize = (info->textureSize >> l) << l;
+
+ /* Set a minimum usable local texture heap size. This will fit
+ * two 256x256x32bpp textures.
+ */
+ if (info->textureSize < 512 * 1024) {
+ info->textureOffset = 0;
+ info->textureSize = 0;
+ }
+
+ /* Reserve space for textures */
+ info->textureOffset = ((disp->fbSize - info->textureSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+
+ /* Reserve space for the shared depth
+ * buffer.
+ */
+ info->depthOffset = ((info->textureOffset - depthSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+ info->depthPitch = disp->virtualWidth;
+
+ info->backOffset = ((info->depthOffset - bufferSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+ info->backPitch = disp->virtualWidth;
+
+
+ fprintf(stderr,
+ "Will use back buffer at offset 0x%x\n",
+ info->backOffset);
+ fprintf(stderr,
+ "Will use depth buffer at offset 0x%x\n",
+ info->depthOffset);
+ fprintf(stderr,
+ "Will use %d kb for textures at offset 0x%x\n",
+ info->textureSize/1024, info->textureOffset);
+
+ info->frontPitchOffset = (((info->frontPitch * cpp / 64) << 22) |
+ (info->frontOffset >> 10));
+
+ info->backPitchOffset = (((info->backPitch * cpp / 64) << 22) |
+ (info->backOffset >> 10));
+
+ info->depthPitchOffset = (((info->depthPitch * cpp / 64) << 22) |
+ (info->depthOffset >> 10));
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the kernel data structures and enable the CP engine.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * This function is a wrapper around the DRM_RADEON_CP_INIT command, passing
+ * all the parameters in a drm_radeon_init_t structure.
+ */
+static int RADEONDRIKernelInit( driDisplay *disp,
+ RADEONInfoPtr info)
+{
+ int cpp = disp->bpp / 8;
+ drm_radeon_init_t drmInfo;
+ int ret;
+
+ memset(&drmInfo, 0, sizeof(drmInfo));
+
+ if ( (info->ChipFamily == CHIP_FAMILY_R200) ||
+ (info->ChipFamily == CHIP_FAMILY_RV250) ||
+ (info->ChipFamily == CHIP_FAMILY_M9) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280) )
+ drmInfo.func = RADEON_INIT_R200_CP;
+ else
+ drmInfo.func = RADEON_INIT_CP;
+
+ /* This is the struct passed to the kernel module for its initialization */
+ drmInfo.sarea_priv_offset = sizeof(drm_sarea_t);
+ drmInfo.cp_mode = RADEON_DEFAULT_CP_BM_MODE;
+ drmInfo.gart_size = info->gartSize*1024*1024;
+ drmInfo.ring_size = info->ringSize*1024*1024;
+ drmInfo.usec_timeout = 1000;
+ drmInfo.fb_bpp = disp->bpp;
+ drmInfo.depth_bpp = disp->bpp;
+ drmInfo.front_offset = info->frontOffset;
+ drmInfo.front_pitch = info->frontPitch * cpp;
+ drmInfo.back_offset = info->backOffset;
+ drmInfo.back_pitch = info->backPitch * cpp;
+ drmInfo.depth_offset = info->depthOffset;
+ drmInfo.depth_pitch = info->depthPitch * cpp;
+ drmInfo.ring_offset = info->ringHandle;
+ drmInfo.ring_rptr_offset = info->ringReadPtrHandle;
+ drmInfo.buffers_offset = info->bufHandle;
+ drmInfo.gart_textures_offset = info->gartTexHandle;
+
+ ret = drmCommandWrite(disp->drmFD, DRM_RADEON_CP_INIT, &drmInfo,
+ sizeof(drm_radeon_init_t));
+
+ return ret >= 0;
+}
+
+
+/**
+ * \brief Add a map for the vertex buffers that will be accessed by any
+ * DRI-based clients.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Calls drmAddBufs() with the previously allocated vertex buffers.
+ */
+static int RADEONDRIBufInit( driDisplay *disp, RADEONInfoPtr info )
+{
+ /* Initialize vertex buffers */
+ info->bufNumBufs = drmAddBufs(disp->drmFD,
+ info->bufMapSize / RADEON_BUFFER_SIZE,
+ RADEON_BUFFER_SIZE,
+ disp->isPCI ? DRM_SG_BUFFER : DRM_AGP_BUFFER,
+ info->bufStart);
+
+ if (info->bufNumBufs <= 0) {
+ fprintf(stderr,
+ "[drm] Could not create vertex/indirect buffers list\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[drm] Added %d %d byte vertex/indirect buffers\n",
+ info->bufNumBufs, RADEON_BUFFER_SIZE);
+
+ return 1;
+}
+
+
+/**
+ * \brief Install an IRQ handler.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * Attempts to install an IRQ handler via drmCtlInstHandler(), falling back to
+ * IRQ-free operation on failure.
+ */
+static void RADEONDRIIrqInit(driDisplay *disp, RADEONInfoPtr info)
+{
+ if ((drmCtlInstHandler(disp->drmFD, 0)) != 0)
+ fprintf(stderr, "[drm] failure adding irq handler, "
+ "there is a device already using that irq\n"
+ "[drm] falling back to irq-free operation\n");
+}
+
+
+/**
+ * \brief Initialize the AGP heap.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * This function is a wrapper around the DRM_RADEON_INIT_HEAP command, passing
+ * all the parameters in a drm_radeon_mem_init_heap structure.
+ */
+static void RADEONDRIAgpHeapInit(driDisplay *disp,
+ RADEONInfoPtr info)
+{
+ drm_radeon_mem_init_heap_t drmHeap;
+
+ /* Start up the simple memory manager for gart space */
+ drmHeap.region = RADEON_MEM_REGION_GART;
+ drmHeap.start = 0;
+ drmHeap.size = info->gartTexMapSize;
+
+ if (drmCommandWrite(disp->drmFD, DRM_RADEON_INIT_HEAP,
+ &drmHeap, sizeof(drmHeap))) {
+ fprintf(stderr,
+ "[drm] Failed to initialized gart heap manager\n");
+ } else {
+ fprintf(stderr,
+ "[drm] Initialized kernel gart heap manager, %d\n",
+ info->gartTexMapSize);
+ }
+}
+
+
+/**
+ * Called at the start of each server generation.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Performs static frame buffer allocation. Opens the DRM device and add maps
+ * to the SAREA, framebuffer and MMIO regions. Fills in \p info with more
+ * information. Creates a \e server context to grab the lock for the
+ * initialization ioctls and calls the other initilization functions in this
+ * file. Starts the CP engine via the DRM_RADEON_CP_START command.
+ *
+ * Setups a RADEONDRIRec structure to be passed to radeon_dri.so for its
+ * initialization.
+ */
+static int RADEONScreenInit( driDisplay *disp, RADEONInfoPtr info, RADEONDRIPtr pRADEONDRI)
+{
+ int i, err;
+
+ {
+ int width_bytes = (disp->virtualWidth * disp->cpp);
+ int maxy = disp->fbSize / width_bytes;
+
+
+ if (maxy <= disp->virtualHeight * 3) {
+ fprintf(stderr,
+ "Static buffer allocation failed -- "
+ "need at least %d kB video memory (have %d kB)\n",
+ (disp->virtualWidth * disp->virtualHeight *
+ disp->cpp * 3 + 1023) / 1024,
+ disp->fbSize / 1024);
+ return 0;
+ }
+ }
+ if (info->ChipFamily >= CHIP_FAMILY_R300) {
+ fprintf(stderr,
+ "Direct rendering not yet supported on "
+ "Radeon 9700 and newer cards\n");
+ return 0;
+ }
+
+ radeon_drm_page_size = getpagesize();
+
+ /* Check the radeon DRM version */
+ if (!RADEONCheckDRMVersion(disp, info)) {
+ return 0;
+ }
+
+ if (disp->isPCI) {
+ /* Initialize PCI */
+ if (!RADEONDRIPciInit(disp, info))
+ return 0;
+ }
+ else {
+ /* Initialize AGP */
+ if (!RADEONDRIAgpInit(disp, info))
+ return 0;
+ }
+
+ /* Memory manager setup */
+ if (!RADEONMemoryInit(disp, info)) {
+ return 0;
+ }
+
+ /* Create a 'server' context so we can grab the lock for
+ * initialization ioctls.
+ */
+ if ((err = drmCreateContext(disp->drmFD, &disp->serverContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+ DRM_LOCK(disp->drmFD, disp->pSAREA, disp->serverContext, 0);
+
+ /* Initialize the kernel data structures */
+ if (!RADEONDRIKernelInit(disp, info)) {
+ fprintf(stderr, "RADEONDRIKernelInit failed\n");
+ DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+ return 0;
+ }
+
+ /* Initialize the vertex buffers list */
+ if (!RADEONDRIBufInit(disp, info)) {
+ fprintf(stderr, "RADEONDRIBufInit failed\n");
+ DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+ return 0;
+ }
+
+ /* Initialize IRQ */
+ RADEONDRIIrqInit(disp, info);
+
+ /* Initialize kernel gart memory manager */
+ RADEONDRIAgpHeapInit(disp, info);
+
+ fprintf(stderr,"page flipping %sabled\n", info->page_flip_enable?"en":"dis");
+ /* Initialize the SAREA private data structure */
+ {
+ drm_radeon_sarea_t *pSAREAPriv;
+ pSAREAPriv = (drm_radeon_sarea_t *)(((char*)disp->pSAREA) +
+ sizeof(drm_sarea_t));
+ memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
+ pSAREAPriv->pfState = info->page_flip_enable;
+ }
+
+ for ( i = 0;; i++ ) {
+ drmMapType type;
+ drmMapFlags flags;
+ drm_handle_t handle, offset;
+ drmSize size;
+ int rc, mtrr;
+
+ if ( ( rc = drmGetMap( disp->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) ) != 0 )
+ break;
+ if ( type == DRM_REGISTERS ) {
+ pRADEONDRI->registerHandle = offset;
+ pRADEONDRI->registerSize = size;
+ break;
+ }
+ }
+ /* Quick hack to clear the front & back buffers. Could also use
+ * the clear ioctl to do this, but would need to setup hw state
+ * first.
+ */
+ drimemsetio((char *)disp->pFB + info->frontOffset,
+ 0xEE,
+ info->frontPitch * disp->cpp * disp->virtualHeight );
+
+ drimemsetio((char *)disp->pFB + info->backOffset,
+ 0x30,
+ info->backPitch * disp->cpp * disp->virtualHeight );
+
+
+ /* This is the struct passed to radeon_dri.so for its initialization */
+ pRADEONDRI->deviceID = info->Chipset;
+ pRADEONDRI->width = disp->virtualWidth;
+ pRADEONDRI->height = disp->virtualHeight;
+ pRADEONDRI->depth = disp->bpp; /* XXX: depth */
+ pRADEONDRI->bpp = disp->bpp;
+ pRADEONDRI->IsPCI = disp->isPCI;
+ pRADEONDRI->frontOffset = info->frontOffset;
+ pRADEONDRI->frontPitch = info->frontPitch;
+ pRADEONDRI->backOffset = info->backOffset;
+ pRADEONDRI->backPitch = info->backPitch;
+ pRADEONDRI->depthOffset = info->depthOffset;
+ pRADEONDRI->depthPitch = info->depthPitch;
+ pRADEONDRI->textureOffset = info->textureOffset;
+ pRADEONDRI->textureSize = info->textureSize;
+ pRADEONDRI->log2TexGran = info->log2TexGran;
+ pRADEONDRI->statusHandle = info->ringReadPtrHandle;
+ pRADEONDRI->statusSize = info->ringReadMapSize;
+ pRADEONDRI->gartTexHandle = info->gartTexHandle;
+ pRADEONDRI->gartTexMapSize = info->gartTexMapSize;
+ pRADEONDRI->log2GARTTexGran = info->log2GARTTexGran;
+ pRADEONDRI->gartTexOffset = info->gartTexStart;
+ pRADEONDRI->sarea_priv_offset = sizeof(drm_sarea_t);
+
+ /* Don't release the lock now - let the VT switch handler do it. */
+
+ return 1;
+}
+
+
+/**
+ * \brief Get Radeon chip family from chipset number.
+ *
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Called by radeonInitFBDev() to set RADEONInfoRec::ChipFamily
+ * according to the value of RADEONInfoRec::Chipset. Fails if the
+ * chipset is unrecognized or not appropriate for this driver (i.e., not
+ * an r100 style radeon)
+ */
+static int get_chipfamily_from_chipset( RADEONInfoPtr info )
+{
+ switch (info->Chipset) {
+ case PCI_CHIP_RADEON_LY:
+ case PCI_CHIP_RADEON_LZ:
+ info->ChipFamily = CHIP_FAMILY_M6;
+ break;
+
+ case PCI_CHIP_RADEON_QY:
+ case PCI_CHIP_RADEON_QZ:
+ info->ChipFamily = CHIP_FAMILY_VE;
+ break;
+
+ case PCI_CHIP_R200_QL:
+ case PCI_CHIP_R200_QN:
+ case PCI_CHIP_R200_QO:
+ case PCI_CHIP_R200_Ql:
+ case PCI_CHIP_R200_BB:
+ info->ChipFamily = CHIP_FAMILY_R200;
+ break;
+
+ case PCI_CHIP_RV200_QW: /* RV200 desktop */
+ case PCI_CHIP_RV200_QX:
+ info->ChipFamily = CHIP_FAMILY_RV200;
+ break;
+
+ case PCI_CHIP_RADEON_LW:
+ case PCI_CHIP_RADEON_LX:
+ info->ChipFamily = CHIP_FAMILY_M7;
+ break;
+
+ case PCI_CHIP_RV250_Id:
+ case PCI_CHIP_RV250_Ie:
+ case PCI_CHIP_RV250_If:
+ case PCI_CHIP_RV250_Ig:
+ info->ChipFamily = CHIP_FAMILY_RV250;
+ break;
+
+ case PCI_CHIP_RV250_Ld:
+ case PCI_CHIP_RV250_Le:
+ case PCI_CHIP_RV250_Lf:
+ case PCI_CHIP_RV250_Lg:
+ info->ChipFamily = CHIP_FAMILY_M9;
+ break;
+
+ case PCI_CHIP_RV280_Y_:
+ case PCI_CHIP_RV280_Ya:
+ case PCI_CHIP_RV280_Yb:
+ case PCI_CHIP_RV280_Yc:
+ info->ChipFamily = CHIP_FAMILY_RV280;
+ break;
+
+ case PCI_CHIP_R300_ND:
+ case PCI_CHIP_R300_NE:
+ case PCI_CHIP_R300_NF:
+ case PCI_CHIP_R300_NG:
+ info->ChipFamily = CHIP_FAMILY_R300;
+ break;
+
+ default:
+ /* Original Radeon/7200 */
+ info->ChipFamily = CHIP_FAMILY_RADEON;
+ }
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the framebuffer device mode
+ *
+ * \param disp display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Fills in \p info with some default values and some information from \p disp
+ * and then calls RADEONScreenInit() for the screen initialization.
+ *
+ * Before exiting clears the framebuffer memory accessing it directly.
+ */
+static int radeonInitFBDev( driDisplay *disp, RADEONDRIPtr pRADEONDRI )
+{
+ int err;
+ RADEONInfoPtr info = calloc(1, sizeof(*info));
+
+ disp->driverPrivate = (void *)info;
+
+ info->gartFastWrite = RADEON_DEFAULT_AGP_FAST_WRITE;
+ info->gartSize = RADEON_DEFAULT_AGP_SIZE;
+ info->gartTexSize = RADEON_DEFAULT_AGP_TEX_SIZE;
+ info->bufSize = RADEON_DEFAULT_BUFFER_SIZE;
+ info->ringSize = RADEON_DEFAULT_RING_SIZE;
+ info->page_flip_enable = RADEON_DEFAULT_PAGE_FLIP;
+
+ info->Chipset = disp->chipset;
+
+ if (!get_chipfamily_from_chipset( info )) {
+ fprintf(stderr, "Unknown or non-radeon chipset -- cannot continue\n");
+ fprintf(stderr, "==> Verify PCI BusID is correct in miniglx.conf\n");
+ return 0;
+ }
+
+ info->frontPitch = disp->virtualWidth;
+
+ if (!RADEONScreenInit( disp, info, pRADEONDRI))
+ return 0;
+
+ /* Initialize and start the CP if required */
+ if ((err = drmCommandNone(disp->drmFD, DRM_RADEON_CP_START)) != 0) {
+ fprintf(stderr, "%s: CP start %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+ return 1;
+}
+
+static EGLBoolean
+radeonFillInConfigs(_EGLDisplay *disp, unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer) {
+ _EGLConfig *configs;
+ _EGLConfig *c;
+ unsigned int i, num_configs;
+ unsigned int depth_buffer_factor;
+ unsigned int back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
+ * enough to add support. Basically, if a context is created with an
+ * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
+ * will never be used.
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
+ };
+
+ u_int8_t depth_bits_array[2];
+ u_int8_t stencil_bits_array[2];
+
+ depth_bits_array[0] = depth_bits;
+ depth_bits_array[1] = depth_bits;
+
+ /* Just like with the accumulation buffer, always provide some modes
+ * with a stencil buffer. It will be a sw fallback, but some apps won't
+ * care about that.
+ */
+ stencil_bits_array[0] = 0;
+ stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
+ back_buffer_factor = (have_back_buffer) ? 2 : 1;
+
+ num_configs = depth_buffer_factor * back_buffer_factor * 2;
+
+ if (pixel_bits == 16) {
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ } else {
+ fb_format = GL_RGBA;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ configs = calloc(sizeof(*configs), num_configs);
+ c = configs;
+ if (!_eglFillInConfigs(c, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array, depth_buffer_factor,
+ back_buffer_modes, back_buffer_factor,
+ GLX_TRUE_COLOR)) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__);
+ return EGL_FALSE;
+ }
+
+ /* Mark the visual as slow if there are "fake" stencil bits.
+ */
+ for (i = 0, c = configs; i < num_configs; i++, c++) {
+ int stencil = GET_CONFIG_ATTRIB(c, EGL_STENCIL_SIZE);
+ if ((stencil != 0) && (stencil != stencil_bits)) {
+ SET_CONFIG_ATTRIB(c, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG);
+ }
+ }
+
+ for (i = 0, c = configs; i < num_configs; i++, c++)
+ _eglAddConfig(disp, c);
+
+ free(configs);
+
+ return EGL_TRUE;
+}
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+static EGLBoolean
+radeonShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+ EGLSurface surface, EGLModeMESA m)
+{
+ _eglDRIShowSurfaceMESA(drv, dpy, screen, surface, m);
+ return EGL_FALSE;
+}
+
+static EGLBoolean
+radeonInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ __DRIframebuffer framebuffer;
+ driDisplay *display;
+
+ if (!_eglDRIInitialize(drv, dpy, major, minor))
+ return EGL_FALSE;
+
+ display = Lookup_driDisplay(dpy);
+
+ framebuffer.dev_priv_size = sizeof(RADEONDRIRec);
+ framebuffer.dev_priv = malloc(sizeof(RADEONDRIRec));
+
+ display->virtualWidth = 1024;
+ display->virtualHeight = 768;
+ display->bpp = 32;
+ display->cpp = 4;
+
+ if (!_eglDRIGetDisplayInfo(display))
+ return EGL_FALSE;
+
+ framebuffer.base = display->pFB;
+ radeonInitFBDev( display, framebuffer.dev_priv );
+
+ if (!_eglDRICreateDisplay(display, &framebuffer))
+ return EGL_FALSE;
+
+ if (!_eglDRICreateScreen(display))
+ return EGL_FALSE;
+
+ radeonFillInConfigs(&display->Base, 32, 24, 8, 1);
+ radeonFillInConfigs(&display->Base, 16, 16, 0, 1);
+
+ drv->Initialized = EGL_TRUE;
+ return EGL_TRUE;
+}
+
+
+/**
+ * The bootstrap function. Return a new radeonDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy)
+{
+ radeonDriver *radeon;
+
+ radeon = (radeonDriver *) calloc(1, sizeof(*radeon));
+ if (!radeon) {
+ return NULL;
+ }
+
+ /* First fill in the dispatch table with defaults */
+ _eglDRIInitDriverFallbacks(&radeon->Base);
+
+ /* then plug in our radeon-specific functions */
+ radeon->Base.Initialize = radeonInitialize;
+ radeon->Base.ShowSurfaceMESA = radeonShowSurfaceMESA;
+
+ return &radeon->Base;
+}