Forgot to add fb_egl.c
authorJon Smirl <jonsmirl@gmail.com>
Sat, 14 May 2005 03:22:48 +0000 (03:22 +0000)
committerJon Smirl <jonsmirl@gmail.com>
Sat, 14 May 2005 03:22:48 +0000 (03:22 +0000)
src/mesa/drivers/dri/fb/fb_egl.c [new file with mode: 0644]

diff --git a/src/mesa/drivers/dri/fb/fb_egl.c b/src/mesa/drivers/dri/fb/fb_egl.c
new file mode 100644 (file)
index 0000000..24a7442
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+ * Test egl driver for fb_dri.so
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h> 
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+
+#include "utils.h"
+#include "buffers.h"
+#include "extensions.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "array_cache/acache.h"
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+#include "drivers/common/driverfuncs.h"
+#include "drirenderbuffer.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"
+
+extern void
+fbSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis);
+
+/**
+ * fb driver-specific driver class derived from _EGLDriver
+ */
+typedef struct fb_driver
+{
+   _EGLDriver Base;  /* base class/object */
+   GLuint fbStuff;
+} fbDriver;
+
+/**
+ * fb display-specific driver class derived from _EGLDisplay
+ */
+typedef struct fb_display
+{
+   _EGLDisplay Base;  /* base class/object */
+   void *pFB;
+} fbDisplay;
+
+/**
+ * fb driver-specific screen class derived from _EGLScreen
+ */
+typedef struct fb_screen
+{
+   _EGLScreen Base;
+   char fb[NAME_MAX];
+} fbScreen;
+
+
+/**
+ * fb driver-specific surface class derived from _EGLSurface
+ */
+typedef struct fb_surface
+{
+   _EGLSurface Base;  /* base class/object */
+   struct gl_framebuffer *mesa_framebuffer;
+} fbSurface;
+
+
+/**
+ * fb driver-specific context class derived from _EGLContext
+ */
+typedef struct fb_context
+{
+   _EGLContext Base;  /* base class/object */
+   GLcontext *glCtx;
+} fbContext;
+
+
+static EGLBoolean
+fbFillInConfigs(_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 * 4;
+
+   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;
+   }
+
+   c = &configs[depth_buffer_factor * back_buffer_factor * 2];
+   if (!_eglFillInConfigs(c, fb_format, fb_type,
+                          depth_bits_array, stencil_bits_array, depth_buffer_factor,
+                          back_buffer_modes, back_buffer_factor,
+                          GLX_DIRECT_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++) {
+      if ((c->glmode.stencilBits != 0)  && (c->glmode.stencilBits != stencil_bits)) {
+         c->glmode.visualRating = GLX_SLOW_CONFIG;
+      }
+   }
+
+   for (i = 0, c = configs; i < num_configs; i++, c++)
+      _eglAddConfig(disp, c);
+      
+   free(configs);
+   
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+fbSetupFramebuffer(fbDisplay *disp, char *fbdev) 
+{
+   int fd;
+   char dev[20];
+   struct fb_var_screeninfo varInfo;
+   struct fb_fix_screeninfo fixedInfo;
+   
+   snprintf(dev, sizeof(dev), "/dev/%s", fbdev);
+
+   /* open the framebuffer device */
+   fd = open(dev, O_RDWR);
+   if (fd < 0) {
+      fprintf(stderr, "Error opening %s: %s\n", fbdev, strerror(errno));
+      return EGL_FALSE;
+   }
+
+   /* get the original variable screen info */
+   if (ioctl(fd, FBIOGET_VSCREENINFO, &varInfo)) {
+      fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+               strerror(errno));
+      return EGL_FALSE;
+   }
+
+   /* Turn off hw accels (otherwise mmap of mmio region will be
+    * refused)
+    */
+   if (varInfo.accel_flags) {
+      varInfo.accel_flags = 0;
+      if (ioctl(fd, FBIOPUT_VSCREENINFO, &varInfo)) {
+         fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
+                  strerror(errno));
+         return EGL_FALSE;
+      }
+   }
+
+   /* Get the fixed screen info */
+   if (ioctl(fd, FBIOGET_FSCREENINFO, &fixedInfo)) {
+      fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+               strerror(errno));
+      return EGL_FALSE;
+   }
+
+   /* mmap the framebuffer into our address space */
+   disp->pFB = (caddr_t)mmap(0,  /* start */
+                      fixedInfo.smem_len,  /* bytes */
+                      PROT_READ | PROT_WRITE,  /* prot */
+                      MAP_SHARED,  /* flags */
+                      fd,  /* fd */
+                      0); /* offset */ 
+   if (disp->pFB == (caddr_t)-1) {
+      fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
+               strerror(errno));
+      return EGL_FALSE;
+   }
+   
+   return EGL_TRUE;
+}
+   
+const char *sysfs = "/sys/class/graphics";
+
+static EGLBoolean
+fbInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   fbDisplay *display;
+   fbScreen *s;
+   _EGLScreen *scrn;
+   char c;
+   unsigned int i, x, y, r;
+   DIR *dir;
+   FILE *file;
+   struct dirent *dirent;
+   char path[NAME_MAX];
+   
+   /* 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;
+   
+   dir = opendir(sysfs);
+   if (!dir)
+      return EGL_FALSE;
+   
+   while (dirent = readdir(dir)) {
+      
+      if (dirent->d_name[0] != 'f')
+         continue;
+      if (dirent->d_name[1] != 'b')
+         continue;
+   
+      if (fbSetupFramebuffer(display, dirent->d_name) == EGL_FALSE)
+         continue;
+         
+      /* Create a screen */
+      s = (fbScreen *) calloc(1, sizeof(fbScreen));
+      if (!s)
+         return EGL_FALSE;
+
+      strncpy(s->fb, dirent->d_name, NAME_MAX);
+      scrn = &s->Base;
+      _eglInitScreen(scrn);
+      _eglAddScreen(&display->Base, scrn);
+      
+      snprintf(path, sizeof(path), "%s/%s/modes", sysfs, s->fb);
+      file = fopen(path, "r");
+      while (fgets(path, sizeof(path), file)) {
+         sscanf(path, "%c:%ux%u-%u", &c, &x, &y, &r);
+         _eglAddMode(scrn, x, y, r * 1000, path);
+      }
+      fclose(file);
+
+      fbFillInConfigs(&display->Base, 32, 24, 8, 1);
+      
+   }
+   closedir(dir);
+
+   drv->Initialized = EGL_TRUE;
+   return EGL_TRUE;
+}
+
+
+static fbDisplay *
+Lookup_fbDisplay(EGLDisplay dpy)
+{
+   _EGLDisplay *d = _eglLookupDisplay(dpy);
+   return (fbDisplay *) d;
+}
+
+
+static fbScreen *
+Lookup_fbScreen(EGLDisplay dpy, EGLScreenMESA screen)
+{
+   _EGLScreen *s = _eglLookupScreen(dpy, screen);
+   return (fbScreen *) s;
+}
+
+
+static fbContext *
+Lookup_fbContext(EGLContext ctx)
+{
+   _EGLContext *c = _eglLookupContext(ctx);
+   return (fbContext *) c;
+}
+
+
+static fbSurface *
+Lookup_fbSurface(EGLSurface surf)
+{
+   _EGLSurface *s = _eglLookupSurface(surf);
+   return (fbSurface *) s;
+}
+
+
+static EGLBoolean
+fbTerminate(_EGLDriver *drv, EGLDisplay dpy)
+{
+   fbDisplay *display = Lookup_fbDisplay(dpy);
+   _eglCleanupDisplay(&display->Base);
+   free(display);
+   free(drv);
+   return EGL_TRUE;
+}
+
+
+static const GLubyte *
+get_string(GLcontext *ctx, GLenum pname)
+{
+   (void) ctx;
+   switch (pname) {
+      case GL_RENDERER:
+         return (const GLubyte *) "Mesa dumb framebuffer";
+      default:
+         return NULL;
+   }
+}
+
+
+static void
+update_state( GLcontext *ctx, GLuint new_state )
+{
+   /* not much to do here - pass it on */
+   _swrast_InvalidateState( ctx, new_state );
+   _swsetup_InvalidateState( ctx, new_state );
+   _ac_InvalidateState( ctx, new_state );
+   _tnl_InvalidateState( ctx, new_state );
+}
+
+
+/**
+ * Called by ctx->Driver.GetBufferSize from in core Mesa to query the
+ * current framebuffer size.
+ */
+static void
+get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
+{
+   *width  = buffer->Width;
+   *height = buffer->Height;
+}
+
+
+static void
+viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+{
+   _mesa_ResizeBuffersMESA();
+}
+
+
+static void
+init_core_functions( struct dd_function_table *functions )
+{
+   functions->GetString = get_string;
+   functions->UpdateState = update_state;
+   functions->ResizeBuffers = _mesa_resize_framebuffer;
+   functions->GetBufferSize = get_buffer_size;
+   functions->Viewport = viewport;
+
+   functions->Clear = _swrast_Clear;  /* could accelerate with blits */
+}
+
+
+static EGLContext
+fbCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
+{
+   GLcontext *ctx;
+   _EGLConfig *conf;
+   fbContext *c;
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   struct dd_function_table functions;
+   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 = (fbContext *) calloc(1, sizeof(fbContext));
+   if (!c)
+      return EGL_NO_CONTEXT;
+
+   _eglInitContext(&c->Base);
+   c->Base.Display = disp;
+   c->Base.Config = conf;
+   c->Base.DrawSurface = EGL_NO_SURFACE;
+   c->Base.ReadSurface = EGL_NO_SURFACE;
+   printf("fbCreateContext\n");
+
+   /* generate handle and insert into hash table */
+   _eglSaveContext(&c->Base);
+   assert(c->Base.Handle);
+
+   /* Init default driver functions then plug in our FBdev-specific functions
+    */
+   _mesa_init_driver_functions(&functions);
+   init_core_functions(&functions);
+
+   ctx = c->glCtx = _mesa_create_context(&conf->glmode, NULL, &functions, (void *)c);
+   if (!c->glCtx) {
+      _mesa_free(c);
+      return GL_FALSE;
+   }
+
+   /* Create module contexts */
+   _swrast_CreateContext( ctx );
+   _ac_CreateContext( ctx );
+   _tnl_CreateContext( ctx );
+   _swsetup_CreateContext( ctx );
+   _swsetup_Wakeup( ctx );
+
+
+   /* swrast init -- need to verify these tests - I just plucked the
+    * numbers out of the air.  (KW)
+    */
+   {
+      struct swrast_device_driver *swdd;
+      swdd = _swrast_GetDeviceDriverReference( ctx );
+   }
+
+   /* use default TCL pipeline */
+   {
+      TNLcontext *tnl = TNL_CONTEXT(ctx);
+      tnl->Driver.RunPipeline = _tnl_run_pipeline;
+   }
+
+   _mesa_enable_sw_extensions(ctx);
+
+   return c->Base.Handle;
+}
+
+
+static EGLSurface
+fbCreateWindowSurface(_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
+fbCreatePixmapSurface(_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
+fbCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
+{
+   _EGLConfig *conf;
+   EGLint i, width = 0, height = 0, largest, texFormat, texTarget, mipmapTex;
+   fbSurface *surf;
+
+   conf = _eglLookupConfig(drv, dpy, config);
+   if (!conf) {
+      _eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
+      return EGL_NO_SURFACE;
+   }
+
+   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+      switch (attrib_list[i]) {
+      case EGL_WIDTH:
+         width = attrib_list[++i];
+         break;
+      case EGL_HEIGHT:
+         height = attrib_list[++i];
+         break;
+      case EGL_LARGEST_PBUFFER:
+         largest = attrib_list[++i];
+         break;
+      case EGL_TEXTURE_FORMAT:
+         texFormat = attrib_list[++i];
+         break;
+      case EGL_TEXTURE_TARGET:
+         texTarget = attrib_list[++i];
+         break;
+      case EGL_MIPMAP_TEXTURE:
+         mipmapTex = attrib_list[++i];
+         break;
+      default:
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
+         return EGL_NO_SURFACE;
+      }
+   }
+
+   if (width <= 0 || height <= 0) {
+      _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface(width or height)");
+      return EGL_NO_SURFACE;
+   }
+
+   surf = (fbSurface *) calloc(1, sizeof(fbSurface));
+   if (!surf)
+      return EGL_NO_SURFACE;
+
+   surf->Base.Config = conf;
+   surf->Base.Type = EGL_PBUFFER_BIT;
+   surf->Base.Width = width;
+   surf->Base.Height = height;
+   surf->Base.TextureFormat = texFormat;
+   surf->Base.TextureTarget = texTarget;
+   surf->Base.MipmapTexture = mipmapTex;
+   surf->Base.MipmapLevel = 0;
+   surf->Base.SwapInterval = 0;
+
+   printf("eglCreatePbufferSurface()\n");
+
+   /* insert into hash table */
+   _eglSaveSurface(&surf->Base);
+   assert(surf->Base.Handle);
+
+   return surf->Base.Handle;
+}
+
+
+static EGLBoolean
+fbDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+   fbSurface *fs = Lookup_fbSurface(surface);
+   _eglRemoveSurface(&fs->Base);
+   if (fs->Base.IsBound) {
+      fs->Base.DeletePending = EGL_TRUE;
+   }
+   else {
+      free(fs);
+   }
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+fbDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
+{
+   fbContext *fc = Lookup_fbContext(context);
+   _eglRemoveContext(&fc->Base);
+   if (fc->Base.IsBound) {
+      fc->Base.DeletePending = EGL_TRUE;
+   }
+   else {
+      free(fc);
+   }
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+fbMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
+{
+   fbSurface *readSurf = Lookup_fbSurface(read);
+   fbSurface *drawSurf = Lookup_fbSurface(draw);
+   fbContext *ctx = Lookup_fbContext(context);
+   EGLBoolean b;
+
+   b = _eglMakeCurrent(drv, dpy, draw, read, context);
+   if (!b)
+      return EGL_FALSE;
+
+   if (ctx) {
+      _mesa_make_current( ctx->glCtx, 
+                           drawSurf->mesa_framebuffer,
+                           readSurf->mesa_framebuffer);
+   } else
+      _mesa_make_current( NULL, NULL, NULL );
+
+   printf("eglMakeCurrent()\n");
+   return EGL_TRUE;
+}
+
+
+static const char *
+fbQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name)
+{
+   if (name == EGL_EXTENSIONS) {
+      return "EGL_MESA_screen_surface";
+   }
+   else {
+      return _eglQueryString(drv, dpy, name);
+   }
+}
+
+
+/**
+ * Create a drawing surface which can be directly displayed on a screen.
+ */
+static EGLSurface
+fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
+                            const EGLint *attrib_list)
+{
+   _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
+   fbDisplay *display = Lookup_fbDisplay(dpy);
+   fbSurface *surface;
+   EGLSurface surf;
+   
+   const GLboolean swDepth = config->glmode.depthBits > 0;
+   const GLboolean swAlpha = config->glmode.alphaBits > 0;
+   const GLboolean swAccum = config->glmode.accumRedBits > 0;
+   const GLboolean swStencil = config->glmode.stencilBits > 0;
+   
+   int bytesPerPixel = config->glmode.rgbBits / 8;
+   int origin = 0;
+   int width, height, stride;
+   
+   surface = (fbSurface *)malloc(sizeof(*surface));
+   surf = _eglInitScreenSurfaceMESA(&surface->Base, drv, dpy, cfg, attrib_list);
+   if (surf == EGL_NO_SURFACE) {
+      free(surface);
+      return EGL_NO_SURFACE;
+   }
+   width = surface->Base.Width;
+   stride = width * bytesPerPixel;
+   height = surface->Base.Height;
+
+   surface->mesa_framebuffer = _mesa_create_framebuffer(&config->glmode);
+   if (!surface->mesa_framebuffer) {
+      free(surface);
+      return EGL_NO_SURFACE;
+   }
+   surface->mesa_framebuffer->Width = width;
+   surface->mesa_framebuffer->Height = height;
+   {
+      driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel, origin, stride);
+      fbSetSpanFunctions(drb, &config->glmode);
+      drb->Base.Data = display->pFB;
+      _mesa_add_renderbuffer(surface->mesa_framebuffer,
+                             BUFFER_FRONT_LEFT, &drb->Base);
+   }
+   if (config->glmode.doubleBufferMode) {
+      driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel, origin, stride);
+      fbSetSpanFunctions(drb, &config->glmode);
+      drb->Base.Data =  _mesa_malloc(stride * height);
+      _mesa_add_renderbuffer(surface->mesa_framebuffer,
+                             BUFFER_BACK_LEFT, &drb->Base);
+   }
+
+   _mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
+                                GL_FALSE, /* color */
+                                swDepth,
+                                swStencil,
+                                swAccum,
+                                0,
+                                GL_FALSE /* aux */);
+   
+   return surf;
+}
+
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+static EGLBoolean
+fbShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+                    EGLSurface surface, EGLModeMESA m)
+{
+   FILE *file;
+   char buffer[NAME_MAX];
+   fbScreen *scrn = Lookup_fbScreen(dpy, screen);
+   fbSurface *surf = Lookup_fbSurface(surface);
+   _EGLMode *mode = _eglLookupMode(dpy, m);
+   
+   if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
+      return EGL_FALSE;
+      
+   snprintf(buffer, sizeof(buffer), "%s/%s/mode", sysfs, scrn->fb);
+   
+   file = fopen(buffer, "r+");
+   fputs(mode->Name, file);
+   fclose(file);
+   
+   snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
+   
+   file = fopen(buffer, "r+");
+   snprintf(buffer, sizeof(buffer), "%d", surf->Base.Config->glmode.rgbBits);
+   fputs(buffer, file);
+   fclose(file);
+
+   return EGL_TRUE;
+}
+
+
+/*
+ * Just to silence warning
+ */
+extern _EGLDriver *
+_eglMain(NativeDisplayType dpy);
+
+
+/**
+ * The bootstrap function.  Return a new fbDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(NativeDisplayType dpy)
+{
+   fbDriver *fb;
+
+   fb = (fbDriver *) calloc(1, sizeof(fbDriver));
+   if (!fb) {
+      return NULL;
+   }
+
+   /* First fill in the dispatch table with defaults */
+   _eglInitDriverFallbacks(&fb->Base);
+   
+   /* then plug in our fb-specific functions */
+   fb->Base.Initialize = fbInitialize;
+   fb->Base.Terminate = fbTerminate;
+   fb->Base.CreateContext = fbCreateContext;
+   fb->Base.MakeCurrent = fbMakeCurrent;
+   fb->Base.CreateWindowSurface = fbCreateWindowSurface;
+   fb->Base.CreatePixmapSurface = fbCreatePixmapSurface;
+   fb->Base.CreatePbufferSurface = fbCreatePbufferSurface;
+   fb->Base.DestroySurface = fbDestroySurface;
+   fb->Base.DestroyContext = fbDestroyContext;
+   fb->Base.QueryString = fbQueryString;
+   fb->Base.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
+   fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
+   
+   return &fb->Base;
+}