aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c')
-rw-r--r--nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c b/nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c
new file mode 100644
index 000000000..2cea48808
--- /dev/null
+++ b/nx-X11/extras/Mesa/src/mesa/drivers/dri/fb/fb_egl.c
@@ -0,0 +1,881 @@
+/*
+ * 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);
+extern void
+fbSetBuffer( GLcontext *ctx, GLframebuffer *colorBuffer, GLuint bufferBit);
+
+/**
+ * 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] = 0;
+ 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;
+}
+
+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;
+ }
+
+ if (fixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
+ struct fb_cmap cmap;
+ unsigned short red[256], green[256], blue[256];
+ int rcols = 1 << varInfo.red.length;
+ int gcols = 1 << varInfo.green.length;
+ int bcols = 1 << varInfo.blue.length;
+ int i;
+
+ cmap.start = 0;
+ cmap.len = gcols;
+ cmap.red = red;
+ cmap.green = green;
+ cmap.blue = blue;
+ cmap.transp = NULL;
+
+ for (i = 0; i < rcols ; i++)
+ red[i] = (65536/(rcols-1)) * i;
+
+ for (i = 0; i < gcols ; i++)
+ green[i] = (65536/(gcols-1)) * i;
+
+ for (i = 0; i < bcols ; i++)
+ blue[i] = (65536/(bcols-1)) * i;
+
+ if (ioctl(fd, FBIOPUTCMAP, (void *) &cmap) < 0) {
+ fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
+ exit(1);
+ }
+ }
+
+ /* mmap the framebuffer into our address space */
+ if (!disp->pFB)
+ 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 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) {
+ printf("EGL - %s framebuffer device not found.", sysfs);
+ return EGL_FALSE;
+ }
+
+ while ((dirent = readdir(dir))) { /* assignment! */
+
+ 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;
+ GLvisual vis;
+ 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;
+
+ /* 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);
+
+ _eglConfigToContextModesRec(conf, &vis);
+
+ ctx = c->glCtx = _mesa_create_context(&vis, 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 );
+ swdd->SetBuffer = fbSetBuffer;
+ }
+
+ /* 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)
+{
+ fbSurface *surf;
+
+ surf = (fbSurface *) calloc(1, sizeof(fbSurface));
+ 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);
+
+ 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);
+ }
+
+ 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 );
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * 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;
+ GLvisual vis;
+ GLcontext *ctx = NULL; /* this should be OK */
+ int origin, bytesPerPixel;
+ int width, height, stride;
+
+ surface = (fbSurface *) 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 Mesa framebuffer */
+ surface->mesa_framebuffer = _mesa_create_framebuffer(&vis);
+ if (!surface->mesa_framebuffer) {
+ free(surface);
+ _eglRemoveSurface(&surface->Base);
+ return EGL_NO_SURFACE;
+ }
+
+ width = surface->Base.Width;
+ height = surface->Base.Height;
+ bytesPerPixel = vis.rgbBits / 8;
+ stride = width * bytesPerPixel;
+ origin = 0;
+
+ /* front color renderbuffer */
+ {
+ driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel,
+ origin, stride);
+ fbSetSpanFunctions(drb, &vis);
+ drb->Base.Data = display->pFB;
+ _mesa_add_renderbuffer(surface->mesa_framebuffer,
+ BUFFER_FRONT_LEFT, &drb->Base);
+ }
+
+ /* back color renderbuffer */
+ if (vis.doubleBufferMode) {
+ driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel,
+ origin, stride);
+ fbSetSpanFunctions(drb, &vis);
+ drb->Base.Data = _mesa_malloc(stride * height);
+ _mesa_add_renderbuffer(surface->mesa_framebuffer,
+ BUFFER_BACK_LEFT, &drb->Base);
+ }
+
+ /* other renderbuffers- software based */
+ _mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
+ GL_FALSE, /* color */
+ vis.haveDepthBuffer,
+ vis.haveStencilBuffer,
+ vis.haveAccumBuffer,
+ GL_FALSE, /* alpha */
+ GL_FALSE /* aux */);
+
+ _mesa_resize_framebuffer(ctx, surface->mesa_framebuffer, width, height);
+
+ 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)
+{
+ fbDisplay *display = Lookup_fbDisplay(dpy);
+ fbScreen *scrn = Lookup_fbScreen(dpy, screen);
+ fbSurface *surf = Lookup_fbSurface(surface);
+ FILE *file;
+ char buffer[NAME_MAX];
+ _EGLMode *mode = _eglLookupMode(dpy, m);
+ int bits;
+
+ if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
+ return EGL_FALSE;
+
+ snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file) {
+err:
+ printf("chown all fb sysfs attrib to allow write - %s\n", buffer);
+ 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/%s/mode", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file)
+ goto err;
+ fputs(mode->Name, file);
+ fclose(file);
+
+ snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
+
+ file = fopen(buffer, "r+");
+ if (!file)
+ goto err;
+ bits = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
+ snprintf(buffer, sizeof(buffer), "%d", bits);
+ fputs(buffer, file);
+ fclose(file);
+
+ fbSetupFramebuffer(display, scrn->fb);
+
+ snprintf(buffer, sizeof(buffer), "%s/%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);
+
+ return EGL_TRUE;
+}
+
+
+/* If the backbuffer is on a videocard, this is extraordinarily slow!
+ */
+static EGLBoolean
+fbSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+{
+ fbContext *context = (fbContext *)_eglGetCurrentContext();
+ fbSurface *fs = Lookup_fbSurface(draw);
+ struct gl_renderbuffer * front_renderbuffer = fs->mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+ void *frontBuffer = front_renderbuffer->Data;
+ int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch;
+ void *backBuffer = fs->mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data;
+
+ if (!_eglSwapBuffers(drv, dpy, draw))
+ return EGL_FALSE;
+
+ if (context) {
+ GLcontext *ctx = context->glCtx;
+
+ if (ctx->Visual.doubleBufferMode) {
+ int i;
+ int offset = 0;
+ char *tmp = _mesa_malloc(currentPitch);
+
+ _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
+
+ ASSERT(frontBuffer);
+ ASSERT(backBuffer);
+
+ for (i = 0; i < fs->Base.Height; i++) {
+ _mesa_memcpy(tmp, (char *) backBuffer + offset,
+ currentPitch);
+ _mesa_memcpy((char *) frontBuffer + offset, tmp,
+ currentPitch);
+ offset += currentPitch;
+ }
+
+ _mesa_free(tmp);
+ }
+ }
+ else {
+ /* XXX this shouldn't be an error but we can't handle it for now */
+ _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n");
+ return EGL_FALSE;
+ }
+ return EGL_TRUE;
+}
+
+
+/**
+ * The bootstrap function. Return a new fbDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *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.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
+ fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
+ fb->Base.SwapBuffers = fbSwapBuffers;
+
+ /* enable supported extensions */
+ fb->Base.MESA_screen_surface = EGL_TRUE;
+ fb->Base.MESA_copy_context = EGL_TRUE;
+
+ return &fb->Base;
+}