517e71f888023aca7fd85867d21e519d1b703bd4
[profile/ivi/mesa.git] / src / mesa / drivers / dri / fb / fb_egl.c
1 /*
2  * Test egl driver for fb_dri.so
3  */
4 #include <assert.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <dirent.h> 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include <sys/mman.h>
13 #include <linux/fb.h>
14
15 #include "utils.h"
16 #include "buffers.h"
17 #include "extensions.h"
18 #include "framebuffer.h"
19 #include "renderbuffer.h"
20 #include "vbo/vbo.h"
21 #include "swrast/swrast.h"
22 #include "swrast_setup/swrast_setup.h"
23 #include "tnl/tnl.h"
24 #include "tnl/t_context.h"
25 #include "tnl/t_pipeline.h"
26 #include "drivers/common/driverfuncs.h"
27 #include "drirenderbuffer.h"
28
29 #include "eglconfig.h"
30 #include "eglcontext.h"
31 #include "egldisplay.h"
32 #include "egldriver.h"
33 #include "eglglobals.h"
34 #include "eglmode.h"
35 #include "eglscreen.h"
36 #include "eglsurface.h"
37
38 extern void
39 fbSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis);
40
41 /**
42  * fb driver-specific driver class derived from _EGLDriver
43  */
44 typedef struct fb_driver
45 {
46    _EGLDriver Base;  /* base class/object */
47    GLuint fbStuff;
48 } fbDriver;
49
50 /**
51  * fb display-specific driver class derived from _EGLDisplay
52  */
53 typedef struct fb_display
54 {
55    _EGLDisplay Base;  /* base class/object */
56    void *pFB;
57 } fbDisplay;
58
59 /**
60  * fb driver-specific screen class derived from _EGLScreen
61  */
62 typedef struct fb_screen
63 {
64    _EGLScreen Base;
65    char fb[NAME_MAX];
66 } fbScreen;
67
68
69 /**
70  * fb driver-specific surface class derived from _EGLSurface
71  */
72 typedef struct fb_surface
73 {
74    _EGLSurface Base;  /* base class/object */
75    struct gl_framebuffer *mesa_framebuffer;
76 } fbSurface;
77
78
79 /**
80  * fb driver-specific context class derived from _EGLContext
81  */
82 typedef struct fb_context
83 {
84    _EGLContext Base;  /* base class/object */
85    GLcontext *glCtx;
86    struct {
87       __DRIcontextPrivate *context;     
88       __DRIscreenPrivate *screen;       
89       __DRIdrawablePrivate *drawable; /* drawable bound to this ctx */
90    } dri;
91 } fbContext, *fbContextPtr;
92
93 #define FB_CONTEXT(ctx)         ((fbContextPtr)(ctx->DriverCtx))
94
95
96 static EGLBoolean
97 fbFillInConfigs(_EGLDisplay *disp, unsigned pixel_bits, unsigned depth_bits,
98                unsigned stencil_bits, GLboolean have_back_buffer) {
99    _EGLConfig *configs;
100    _EGLConfig *c;
101    unsigned int i, num_configs;
102    unsigned int depth_buffer_factor;
103    unsigned int back_buffer_factor;
104    GLenum fb_format;
105    GLenum fb_type;
106
107    /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
108    * enough to add support.  Basically, if a context is created with an
109    * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
110    * will never be used.
111    */
112    static const GLenum back_buffer_modes[] = {
113             GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
114          };
115
116    u_int8_t depth_bits_array[2];
117    u_int8_t stencil_bits_array[2];
118
119    depth_bits_array[0] = 0;
120    depth_bits_array[1] = depth_bits;
121
122    /* Just like with the accumulation buffer, always provide some modes
123    * with a stencil buffer.  It will be a sw fallback, but some apps won't
124    * care about that.
125    */
126    stencil_bits_array[0] = 0;
127    stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
128
129    depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
130    back_buffer_factor = (have_back_buffer) ? 2 : 1;
131
132    num_configs = depth_buffer_factor * back_buffer_factor * 2;
133
134    if (pixel_bits == 16) {
135       fb_format = GL_RGB;
136       fb_type = GL_UNSIGNED_SHORT_5_6_5;
137    } else {
138       fb_format = GL_RGBA;
139       fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
140    }
141
142    configs = calloc(sizeof(*configs), num_configs);
143    c = configs;
144    if (!_eglFillInConfigs(c, fb_format, fb_type,
145                           depth_bits_array, stencil_bits_array, depth_buffer_factor,
146                           back_buffer_modes, back_buffer_factor,
147                           GLX_TRUE_COLOR)) {
148       fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
149                __func__, __LINE__);
150       return EGL_FALSE;
151    }
152
153    /* Mark the visual as slow if there are "fake" stencil bits.
154    */
155    for (i = 0, c = configs; i < num_configs; i++, c++) {
156       int stencil = GET_CONFIG_ATTRIB(c, EGL_STENCIL_SIZE);
157       if ((stencil != 0)  && (stencil != stencil_bits)) {
158          SET_CONFIG_ATTRIB(c, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG);
159       }
160    }
161
162    for (i = 0, c = configs; i < num_configs; i++, c++)
163       _eglAddConfig(disp, c);
164       
165    free(configs);
166    
167    return EGL_TRUE;
168 }
169
170 static EGLBoolean
171 fbSetupFramebuffer(fbDisplay *disp, char *fbdev) 
172 {
173    int fd;
174    char dev[20];
175    struct fb_var_screeninfo varInfo;
176    struct fb_fix_screeninfo fixedInfo;
177    
178    snprintf(dev, sizeof(dev), "/dev/%s", fbdev);
179
180    /* open the framebuffer device */
181    fd = open(dev, O_RDWR);
182    if (fd < 0) {
183       fprintf(stderr, "Error opening %s: %s\n", fbdev, strerror(errno));
184       return EGL_FALSE;
185    }
186
187    /* get the original variable screen info */
188    if (ioctl(fd, FBIOGET_VSCREENINFO, &varInfo)) {
189       fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
190                strerror(errno));
191       return EGL_FALSE;
192    }
193
194    /* Turn off hw accels (otherwise mmap of mmio region will be
195     * refused)
196     */
197    if (varInfo.accel_flags) {
198       varInfo.accel_flags = 0;
199       if (ioctl(fd, FBIOPUT_VSCREENINFO, &varInfo)) {
200          fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
201                   strerror(errno));
202          return EGL_FALSE;
203       }
204    }
205
206    /* Get the fixed screen info */
207    if (ioctl(fd, FBIOGET_FSCREENINFO, &fixedInfo)) {
208       fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
209                strerror(errno));
210       return EGL_FALSE;
211    }
212    
213    if (fixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
214       struct fb_cmap cmap;
215       unsigned short red[256], green[256], blue[256];
216       int rcols = 1 << varInfo.red.length;
217       int gcols = 1 << varInfo.green.length;
218       int bcols = 1 << varInfo.blue.length;
219       int i;
220
221       cmap.start = 0;      
222       cmap.len = gcols;
223       cmap.red   = red;
224       cmap.green = green;
225       cmap.blue  = blue;
226       cmap.transp = NULL;
227
228       for (i = 0; i < rcols ; i++) 
229          red[i] = (65536/(rcols-1)) * i;
230
231       for (i = 0; i < gcols ; i++) 
232          green[i] = (65536/(gcols-1)) * i;
233
234       for (i = 0; i < bcols ; i++) 
235          blue[i] = (65536/(bcols-1)) * i;
236       
237       if (ioctl(fd, FBIOPUTCMAP, (void *) &cmap) < 0) {
238          fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
239          exit(1);
240       }
241    }
242
243    /* mmap the framebuffer into our address space */
244    if (!disp->pFB)
245       disp->pFB = (caddr_t)mmap(0,  /* start */
246                       fixedInfo.smem_len,  /* bytes */
247                       PROT_READ | PROT_WRITE,  /* prot */
248                       MAP_SHARED,  /* flags */
249                       fd,  /* fd */
250                       0); /* offset */ 
251    if (disp->pFB == (caddr_t)-1) {
252       fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
253                strerror(errno));
254       return EGL_FALSE;
255    }
256    
257    return EGL_TRUE;
258 }
259    
260 const char *sysfs = "/sys/class/graphics";
261
262 static EGLBoolean
263 fbInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
264 {
265    _EGLDisplay *disp = _eglLookupDisplay(dpy);
266    fbDisplay *display;
267    fbScreen *s;
268    _EGLScreen *scrn;
269    char c;
270    unsigned int x, y, r;
271    DIR *dir;
272    FILE *file;
273    struct dirent *dirent;
274    char path[NAME_MAX];
275    
276    /* Switch display structure to one with our private fields */
277    display = calloc(1, sizeof(*display));
278    display->Base = *disp;
279    _eglHashInsert(_eglGlobal.Displays, disp->Handle, display);
280    free(disp);
281    
282    *major = 1;
283    *minor = 0;
284    
285    dir = opendir(sysfs);
286    if (!dir) {
287       printf("EGL - %s framebuffer device not found.", sysfs);
288       return EGL_FALSE;
289    }
290    
291    while ((dirent = readdir(dir))) {  /* assignment! */
292       
293       if (dirent->d_name[0] != 'f')
294          continue;
295       if (dirent->d_name[1] != 'b')
296          continue;
297    
298       if (fbSetupFramebuffer(display, dirent->d_name) == EGL_FALSE)
299          continue;
300          
301       /* Create a screen */
302       s = (fbScreen *) calloc(1, sizeof(fbScreen));
303       if (!s)
304          return EGL_FALSE;
305
306       strncpy(s->fb, dirent->d_name, NAME_MAX);
307       scrn = &s->Base;
308       _eglInitScreen(scrn);
309       _eglAddScreen(&display->Base, scrn);
310       
311       snprintf(path, sizeof(path), "%s/%s/modes", sysfs, s->fb);
312       file = fopen(path, "r");
313       while (fgets(path, sizeof(path), file)) {
314          sscanf(path, "%c:%ux%u-%u", &c, &x, &y, &r);
315          _eglAddMode(scrn, x, y, r * 1000, path);
316       }
317       fclose(file);
318
319       fbFillInConfigs(&display->Base, 32, 24, 8, 1);
320       
321    }
322    closedir(dir);
323
324    drv->Initialized = EGL_TRUE;
325    return EGL_TRUE;
326 }
327
328
329 static fbDisplay *
330 Lookup_fbDisplay(EGLDisplay dpy)
331 {
332    _EGLDisplay *d = _eglLookupDisplay(dpy);
333    return (fbDisplay *) d;
334 }
335
336
337 static fbScreen *
338 Lookup_fbScreen(EGLDisplay dpy, EGLScreenMESA screen)
339 {
340    _EGLScreen *s = _eglLookupScreen(dpy, screen);
341    return (fbScreen *) s;
342 }
343
344
345 static fbContext *
346 Lookup_fbContext(EGLContext ctx)
347 {
348    _EGLContext *c = _eglLookupContext(ctx);
349    return (fbContext *) c;
350 }
351
352
353 static fbSurface *
354 Lookup_fbSurface(EGLSurface surf)
355 {
356    _EGLSurface *s = _eglLookupSurface(surf);
357    return (fbSurface *) s;
358 }
359
360
361 static EGLBoolean
362 fbTerminate(_EGLDriver *drv, EGLDisplay dpy)
363 {
364    fbDisplay *display = Lookup_fbDisplay(dpy);
365    _eglCleanupDisplay(&display->Base);
366    free(display);
367    free(drv);
368    return EGL_TRUE;
369 }
370
371
372 static const GLubyte *
373 get_string(GLcontext *ctx, GLenum pname)
374 {
375    (void) ctx;
376    switch (pname) {
377       case GL_RENDERER:
378          return (const GLubyte *) "Mesa dumb framebuffer";
379       default:
380          return NULL;
381    }
382 }
383
384
385 static void
386 update_state( GLcontext *ctx, GLuint new_state )
387 {
388    /* not much to do here - pass it on */
389    _swrast_InvalidateState( ctx, new_state );
390    _swsetup_InvalidateState( ctx, new_state );
391    _vbo_InvalidateState( ctx, new_state );
392    _tnl_InvalidateState( ctx, new_state );
393 }
394
395
396 /**
397  * Called by ctx->Driver.GetBufferSize from in core Mesa to query the
398  * current framebuffer size.
399  */
400 static void
401 get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
402 {
403    *width  = buffer->Width;
404    *height = buffer->Height;
405 }
406
407
408 static void
409 updateFramebufferSize(GLcontext *ctx)
410 {
411    fbContextPtr fbmesa = FB_CONTEXT(ctx);
412    struct gl_framebuffer *fb = ctx->WinSysDrawBuffer;
413    if (fbmesa->dri.drawable->w != fb->Width ||
414        fbmesa->dri.drawable->h != fb->Height) {
415       driUpdateFramebufferSize(ctx, fbmesa->dri.drawable);
416    }
417 }
418
419 static void
420 viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
421 {
422    /* XXX this should be called after we acquire the DRI lock, not here */
423    updateFramebufferSize(ctx);
424 }
425
426
427 static void
428 init_core_functions( struct dd_function_table *functions )
429 {
430    functions->GetString = get_string;
431    functions->UpdateState = update_state;
432    functions->GetBufferSize = get_buffer_size;
433    functions->Viewport = viewport;
434
435    functions->Clear = _swrast_Clear;  /* could accelerate with blits */
436 }
437
438
439 static EGLContext
440 fbCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
441 {
442    GLcontext *ctx;
443    _EGLConfig *conf;
444    fbContext *c;
445    _EGLDisplay *disp = _eglLookupDisplay(dpy);
446    struct dd_function_table functions;
447    GLvisual vis;
448    int i;
449
450    conf = _eglLookupConfig(drv, dpy, config);
451    if (!conf) {
452       _eglError(EGL_BAD_CONFIG, "eglCreateContext");
453       return EGL_NO_CONTEXT;
454    }
455
456    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
457       switch (attrib_list[i]) {
458          /* no attribs defined for now */
459       default:
460          _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
461          return EGL_NO_CONTEXT;
462       }
463    }
464
465    c = (fbContext *) calloc(1, sizeof(fbContext));
466    if (!c)
467       return EGL_NO_CONTEXT;
468
469    _eglInitContext(&c->Base);
470    c->Base.Display = disp;
471    c->Base.Config = conf;
472    c->Base.DrawSurface = EGL_NO_SURFACE;
473    c->Base.ReadSurface = EGL_NO_SURFACE;
474
475    /* generate handle and insert into hash table */
476    _eglSaveContext(&c->Base);
477    assert(c->Base.Handle);
478
479    /* Init default driver functions then plug in our FBdev-specific functions
480     */
481    _mesa_init_driver_functions(&functions);
482    init_core_functions(&functions);
483
484    _eglConfigToContextModesRec(conf, &vis);
485
486    ctx = c->glCtx = _mesa_create_context(&vis, NULL, &functions, (void *)c);
487    if (!c->glCtx) {
488       _mesa_free(c);
489       return GL_FALSE;
490    }
491
492    /* Create module contexts */
493    _swrast_CreateContext( ctx );
494    _vbo_CreateContext( ctx );
495    _tnl_CreateContext( ctx );
496    _swsetup_CreateContext( ctx );
497    _swsetup_Wakeup( ctx );
498
499
500    /* use default TCL pipeline */
501    {
502       TNLcontext *tnl = TNL_CONTEXT(ctx);
503       tnl->Driver.RunPipeline = _tnl_run_pipeline;
504    }
505
506    _mesa_enable_sw_extensions(ctx);
507
508    return c->Base.Handle;
509 }
510
511
512 static EGLSurface
513 fbCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
514 {
515    int i;
516    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
517       switch (attrib_list[i]) {
518          /* no attribs at this time */
519       default:
520          _eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface");
521          return EGL_NO_SURFACE;
522       }
523    }
524    printf("eglCreateWindowSurface()\n");
525    /* XXX unfinished */
526
527    return EGL_NO_SURFACE;
528 }
529
530
531 static EGLSurface
532 fbCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
533 {
534    _EGLConfig *conf;
535    EGLint i;
536
537    conf = _eglLookupConfig(drv, dpy, config);
538    if (!conf) {
539       _eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface");
540       return EGL_NO_SURFACE;
541    }
542
543    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
544       switch (attrib_list[i]) {
545          /* no attribs at this time */
546       default:
547          _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
548          return EGL_NO_SURFACE;
549       }
550    }
551
552    if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) {
553       _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface");
554       return EGL_NO_SURFACE;
555    }
556
557    printf("eglCreatePixmapSurface()\n");
558    return EGL_NO_SURFACE;
559 }
560
561
562 static EGLSurface
563 fbCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
564 {
565    fbSurface *surf;
566
567    surf = (fbSurface *) calloc(1, sizeof(fbSurface));
568    if (!surf) {
569       return EGL_NO_SURFACE;
570    }
571
572    if (_eglInitPbufferSurface(&surf->Base, drv, dpy, config, attrib_list) == EGL_NO_SURFACE) {
573       free(surf);
574       return EGL_NO_SURFACE;
575    }
576
577    /* create software-based pbuffer */
578    {
579       GLcontext *ctx = NULL; /* this _should_ be OK */
580       GLvisual vis;
581       _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
582       assert(conf); /* bad config should be caught earlier */
583       _eglConfigToContextModesRec(conf, &vis);
584
585       surf->mesa_framebuffer = _mesa_create_framebuffer(&vis);
586       _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
587                                    GL_TRUE, /* color bufs */
588                                    vis.haveDepthBuffer,
589                                    vis.haveStencilBuffer,
590                                    vis.haveAccumBuffer,
591                                    GL_FALSE, /* alpha */
592                                    GL_FALSE /* aux */ );
593
594       /* set pbuffer/framebuffer size */
595       _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
596                                surf->Base.Width, surf->Base.Height);
597    }
598
599    return surf->Base.Handle;
600 }
601
602
603 static EGLBoolean
604 fbDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
605 {
606    fbSurface *fs = Lookup_fbSurface(surface);
607    _eglRemoveSurface(&fs->Base);
608    if (fs->Base.IsBound) {
609       fs->Base.DeletePending = EGL_TRUE;
610    }
611    else {
612       free(fs);
613    }
614    return EGL_TRUE;
615 }
616
617
618 static EGLBoolean
619 fbDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
620 {
621    fbContext *fc = Lookup_fbContext(context);
622    _eglRemoveContext(&fc->Base);
623    if (fc->Base.IsBound) {
624       fc->Base.DeletePending = EGL_TRUE;
625    }
626    else {
627       free(fc);
628    }
629    return EGL_TRUE;
630 }
631
632
633 static EGLBoolean
634 fbMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
635 {
636    fbSurface *readSurf = Lookup_fbSurface(read);
637    fbSurface *drawSurf = Lookup_fbSurface(draw);
638    fbContext *ctx = Lookup_fbContext(context);
639    EGLBoolean b;
640
641    b = _eglMakeCurrent(drv, dpy, draw, read, context);
642    if (!b)
643       return EGL_FALSE;
644
645    if (ctx) {
646       _mesa_make_current( ctx->glCtx, 
647                            drawSurf->mesa_framebuffer,
648                            readSurf->mesa_framebuffer);
649    } else
650       _mesa_make_current( NULL, NULL, NULL );
651
652    return EGL_TRUE;
653 }
654
655
656 /**
657  * Create a drawing surface which can be directly displayed on a screen.
658  */
659 static EGLSurface
660 fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
661                           const EGLint *attrib_list)
662 {
663    _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
664    fbDisplay *display = Lookup_fbDisplay(dpy);
665    fbSurface *surface;
666    EGLSurface surf;
667    GLvisual vis;
668    GLcontext *ctx = NULL; /* this should be OK */
669    int origin, bytesPerPixel;
670    int width, height, stride;
671    
672    surface = (fbSurface *) malloc(sizeof(*surface));
673    if (!surface) {
674       return EGL_NO_SURFACE;
675    }
676
677    /* init base class, error check, etc. */
678    surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list);
679    if (surf == EGL_NO_SURFACE) {
680       free(surface);
681       return EGL_NO_SURFACE;
682    }
683
684    /* convert EGLConfig to GLvisual */
685    _eglConfigToContextModesRec(config, &vis);
686
687    /* create Mesa framebuffer */
688    surface->mesa_framebuffer = _mesa_create_framebuffer(&vis);
689    if (!surface->mesa_framebuffer) {
690       free(surface);
691       _eglRemoveSurface(&surface->Base);
692       return EGL_NO_SURFACE;
693    }
694
695    width = surface->Base.Width;
696    height = surface->Base.Height;
697    bytesPerPixel = vis.rgbBits / 8;
698    stride = width * bytesPerPixel;
699    origin = 0;
700
701    /* front color renderbuffer */
702    {
703       driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, display->pFB,
704                                                 bytesPerPixel,
705                                                 origin, stride, NULL);
706       fbSetSpanFunctions(drb, &vis);
707       _mesa_add_renderbuffer(surface->mesa_framebuffer,
708                              BUFFER_FRONT_LEFT, &drb->Base);
709    }
710
711    /* back color renderbuffer */
712    if (vis.doubleBufferMode) {
713       GLubyte *backBuf = _mesa_malloc(stride * height);
714       driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, backBuf,
715                                                 bytesPerPixel,
716                                                 origin, stride, NULL);
717       fbSetSpanFunctions(drb, &vis);
718       _mesa_add_renderbuffer(surface->mesa_framebuffer,
719                              BUFFER_BACK_LEFT, &drb->Base);
720    }
721
722    /* other renderbuffers- software based */
723    _mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
724                                 GL_FALSE, /* color */
725                                 vis.haveDepthBuffer,
726                                 vis.haveStencilBuffer,
727                                 vis.haveAccumBuffer,
728                                 GL_FALSE, /* alpha */
729                                 GL_FALSE /* aux */);
730    
731    _mesa_resize_framebuffer(ctx, surface->mesa_framebuffer, width, height);
732
733    return surf;
734 }
735
736
737 /**
738  * Show the given surface on the named screen.
739  * If surface is EGL_NO_SURFACE, disable the screen's output.
740  */
741 static EGLBoolean
742 fbShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
743                     EGLSurface surface, EGLModeMESA m)
744 {
745    fbDisplay *display = Lookup_fbDisplay(dpy);
746    fbScreen *scrn = Lookup_fbScreen(dpy, screen);
747    fbSurface *surf = Lookup_fbSurface(surface);
748    FILE *file;
749    char buffer[NAME_MAX];
750    _EGLMode *mode = _eglLookupMode(dpy, m);
751    int bits;
752    
753    if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
754       return EGL_FALSE;
755       
756    snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
757    
758    file = fopen(buffer, "r+");
759    if (!file) {
760 err:
761       printf("chown all fb sysfs attrib to allow write - %s\n", buffer);
762       return EGL_FALSE;
763    }
764    snprintf(buffer, sizeof(buffer), "%d", (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
765    fputs(buffer, file);
766    fclose(file);
767    
768    if (m == EGL_NO_MODE_MESA)
769       return EGL_TRUE;
770    
771    snprintf(buffer, sizeof(buffer), "%s/%s/mode", sysfs, scrn->fb);
772    
773    file = fopen(buffer, "r+");
774    if (!file)
775       goto err;
776    fputs(mode->Name, file);
777    fclose(file);
778    
779    snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
780    
781    file = fopen(buffer, "r+");
782    if (!file)
783       goto err;
784    bits = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
785    snprintf(buffer, sizeof(buffer), "%d", bits);
786    fputs(buffer, file);
787    fclose(file);
788
789    fbSetupFramebuffer(display, scrn->fb);
790    
791    snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
792    
793    file = fopen(buffer, "r+");
794    if (!file)
795       goto err;
796       
797    snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
798    fputs(buffer, file);
799    fclose(file);
800    
801    return EGL_TRUE;
802 }
803
804
805 /* If the backbuffer is on a videocard, this is extraordinarily slow!
806  */
807 static EGLBoolean
808 fbSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
809 {
810    fbContext *context = (fbContext *)_eglGetCurrentContext();
811    fbSurface *fs =  Lookup_fbSurface(draw);
812    struct gl_renderbuffer * front_renderbuffer = fs->mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
813    void *frontBuffer = front_renderbuffer->Data;
814    int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch;
815    void *backBuffer = fs->mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data;
816
817    if (!_eglSwapBuffers(drv, dpy, draw))
818       return EGL_FALSE;
819
820    if (context) {
821       GLcontext *ctx = context->glCtx;
822       
823       if (ctx->Visual.doubleBufferMode) {
824          int i;
825          int offset = 0;
826          char *tmp = _mesa_malloc(currentPitch);
827
828          _mesa_notifySwapBuffers( ctx );  /* flush pending rendering comands */
829
830          ASSERT(frontBuffer);
831          ASSERT(backBuffer);
832
833          for (i = 0; i < fs->Base.Height; i++) {
834             _mesa_memcpy(tmp, (char *) backBuffer + offset,
835                          currentPitch);
836             _mesa_memcpy((char *) frontBuffer + offset, tmp,
837                           currentPitch);
838             offset += currentPitch;
839          }
840             
841          _mesa_free(tmp);
842       }
843    }
844    else {
845       /* XXX this shouldn't be an error but we can't handle it for now */
846       _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n");
847       return EGL_FALSE;
848    }
849    return EGL_TRUE;
850 }
851
852
853 /**
854  * The bootstrap function.  Return a new fbDriver object and
855  * plug in API functions.
856  */
857 _EGLDriver *
858 _eglMain(_EGLDisplay *dpy)
859 {
860    fbDriver *fb;
861
862    fb = (fbDriver *) calloc(1, sizeof(fbDriver));
863    if (!fb) {
864       return NULL;
865    }
866
867    /* First fill in the dispatch table with defaults */
868    _eglInitDriverFallbacks(&fb->Base);
869    
870    /* then plug in our fb-specific functions */
871    fb->Base.Initialize = fbInitialize;
872    fb->Base.Terminate = fbTerminate;
873    fb->Base.CreateContext = fbCreateContext;
874    fb->Base.MakeCurrent = fbMakeCurrent;
875    fb->Base.CreateWindowSurface = fbCreateWindowSurface;
876    fb->Base.CreatePixmapSurface = fbCreatePixmapSurface;
877    fb->Base.CreatePbufferSurface = fbCreatePbufferSurface;
878    fb->Base.DestroySurface = fbDestroySurface;
879    fb->Base.DestroyContext = fbDestroyContext;
880    fb->Base.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
881    fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
882    fb->Base.SwapBuffers = fbSwapBuffers;
883    
884    /* enable supported extensions */
885    fb->Base.MESA_screen_surface = EGL_TRUE;
886    fb->Base.MESA_copy_context = EGL_TRUE;
887
888    return &fb->Base;
889 }