mesa: Don't bind DRAW/READ_FRAMEBUFFER separately without FBO blit support
[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 "main/extensions.h"
18 #include "main/framebuffer.h"
19 #include "main/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/tcontext.h"
25 #include "tnl/t_pipeline.h"
26 #include "drivers/common/driverfuncs.h"
27 #include "drirenderbuffer.h"
28
29 #include "eglconfig.h"
30 #include "eglmain/context.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 uint8_t depth_bits_array[2];
117 uint8_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 /* link to display */
476 _eglLinkContext(&c->Base, disp);
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 _eglUnlinkSurface(&fs->Base);
608 if (!_eglIsSurfaceBound(&fs->Base))
609 free(fs);
610 return EGL_TRUE;
611 }
612
613
614 static EGLBoolean
615 fbDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
616 {
617 fbContext *fc = Lookup_fbContext(context);
618 _eglUnlinkContext(&fc->Base);
619 if (!_eglIsContextBound(&fc->Base))
620 free(fc);
621 return EGL_TRUE;
622 }
623
624
625 static EGLBoolean
626 fbMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
627 {
628 fbSurface *readSurf = Lookup_fbSurface(read);
629 fbSurface *drawSurf = Lookup_fbSurface(draw);
630 fbContext *ctx = Lookup_fbContext(context);
631 EGLBoolean b;
632
633 b = _eglMakeCurrent(drv, dpy, draw, read, context);
634 if (!b)
635 return EGL_FALSE;
636
637 if (ctx) {
638 _mesa_make_current( ctx->glCtx,
639 drawSurf->mesa_framebuffer,
640 readSurf->mesa_framebuffer);
641 } else
642 _mesa_make_current( NULL, NULL, NULL );
643
644 return EGL_TRUE;
645 }
646
647
648 /**
649 * Create a drawing surface which can be directly displayed on a screen.
650 */
651 static EGLSurface
652 fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
653 const EGLint *attrib_list)
654 {
655 _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
656 fbDisplay *display = Lookup_fbDisplay(dpy);
657 fbSurface *surface;
658 EGLSurface surf;
659 GLvisual vis;
660 GLcontext *ctx = NULL; /* this should be OK */
661 int origin, bytesPerPixel;
662 int width, height, stride;
663
664 surface = (fbSurface *) malloc(sizeof(*surface));
665 if (!surface) {
666 return EGL_NO_SURFACE;
667 }
668
669 /* init base class, error check, etc. */
670 surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list);
671 if (surf == EGL_NO_SURFACE) {
672 free(surface);
673 return EGL_NO_SURFACE;
674 }
675
676 /* convert EGLConfig to GLvisual */
677 _eglConfigToContextModesRec(config, &vis);
678
679 /* create Mesa framebuffer */
680 surface->mesa_framebuffer = _mesa_create_framebuffer(&vis);
681 if (!surface->mesa_framebuffer) {
682 free(surface);
683 _eglUnlinkSurface(&surface->Base);
684 return EGL_NO_SURFACE;
685 }
686
687 width = surface->Base.Width;
688 height = surface->Base.Height;
689 bytesPerPixel = vis.rgbBits / 8;
690 stride = width * bytesPerPixel;
691 origin = 0;
692
693 /* front color renderbuffer */
694 {
695 driRenderbuffer *drb = driNewRenderbuffer(MESA_FORMAT_ARGB8888, display->pFB,
696 bytesPerPixel,
697 origin, stride, NULL);
698 fbSetSpanFunctions(drb, &vis);
699 _mesa_add_renderbuffer(surface->mesa_framebuffer,
700 BUFFER_FRONT_LEFT, &drb->Base);
701 }
702
703 /* back color renderbuffer */
704 if (vis.doubleBufferMode) {
705 GLubyte *backBuf = _mesa_malloc(stride * height);
706 driRenderbuffer *drb = driNewRenderbuffer(MESA_FORMAT_ARGB8888, backBuf,
707 bytesPerPixel,
708 origin, stride, NULL);
709 fbSetSpanFunctions(drb, &vis);
710 _mesa_add_renderbuffer(surface->mesa_framebuffer,
711 BUFFER_BACK_LEFT, &drb->Base);
712 }
713
714 /* other renderbuffers- software based */
715 _mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
716 GL_FALSE, /* color */
717 vis.haveDepthBuffer,
718 vis.haveStencilBuffer,
719 vis.haveAccumBuffer,
720 GL_FALSE, /* alpha */
721 GL_FALSE /* aux */);
722
723 _mesa_resize_framebuffer(ctx, surface->mesa_framebuffer, width, height);
724
725 return surf;
726 }
727
728
729 /**
730 * Show the given surface on the named screen.
731 * If surface is EGL_NO_SURFACE, disable the screen's output.
732 */
733 static EGLBoolean
734 fbShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
735 EGLSurface surface, EGLModeMESA m)
736 {
737 fbDisplay *display = Lookup_fbDisplay(dpy);
738 fbScreen *scrn = Lookup_fbScreen(dpy, screen);
739 fbSurface *surf = Lookup_fbSurface(surface);
740 FILE *file;
741 char buffer[NAME_MAX];
742 _EGLMode *mode = _eglLookupMode(dpy, m);
743 int bits;
744
745 if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
746 return EGL_FALSE;
747
748 snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
749
750 file = fopen(buffer, "r+");
751 if (!file) {
752 err:
753 printf("chown all fb sysfs attrib to allow write - %s\n", buffer);
754 return EGL_FALSE;
755 }
756 snprintf(buffer, sizeof(buffer), "%d", (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
757 fputs(buffer, file);
758 fclose(file);
759
760 if (m == EGL_NO_MODE_MESA)
761 return EGL_TRUE;
762
763 snprintf(buffer, sizeof(buffer), "%s/%s/mode", sysfs, scrn->fb);
764
765 file = fopen(buffer, "r+");
766 if (!file)
767 goto err;
768 fputs(mode->Name, file);
769 fclose(file);
770
771 snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
772
773 file = fopen(buffer, "r+");
774 if (!file)
775 goto err;
776 bits = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
777 snprintf(buffer, sizeof(buffer), "%d", bits);
778 fputs(buffer, file);
779 fclose(file);
780
781 fbSetupFramebuffer(display, scrn->fb);
782
783 snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
784
785 file = fopen(buffer, "r+");
786 if (!file)
787 goto err;
788
789 snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
790 fputs(buffer, file);
791 fclose(file);
792
793 return EGL_TRUE;
794 }
795
796
797 /* If the backbuffer is on a videocard, this is extraordinarily slow!
798 */
799 static EGLBoolean
800 fbSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
801 {
802 fbContext *context = (fbContext *)_eglGetCurrentContext();
803 fbSurface *fs = Lookup_fbSurface(draw);
804 struct gl_renderbuffer * front_renderbuffer = fs->mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
805 void *frontBuffer = front_renderbuffer->Data;
806 int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch;
807 void *backBuffer = fs->mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data;
808
809 if (!_eglSwapBuffers(drv, dpy, draw))
810 return EGL_FALSE;
811
812 if (context) {
813 GLcontext *ctx = context->glCtx;
814
815 if (ctx->Visual.doubleBufferMode) {
816 int i;
817 int offset = 0;
818 char *tmp = _mesa_malloc(currentPitch);
819
820 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
821
822 ASSERT(frontBuffer);
823 ASSERT(backBuffer);
824
825 for (i = 0; i < fs->Base.Height; i++) {
826 _mesa_memcpy(tmp, (char *) backBuffer + offset,
827 currentPitch);
828 _mesa_memcpy((char *) frontBuffer + offset, tmp,
829 currentPitch);
830 offset += currentPitch;
831 }
832
833 _mesa_free(tmp);
834 }
835 }
836 else {
837 /* XXX this shouldn't be an error but we can't handle it for now */
838 _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n");
839 return EGL_FALSE;
840 }
841 return EGL_TRUE;
842 }
843
844
845 /**
846 * The bootstrap function. Return a new fbDriver object and
847 * plug in API functions.
848 */
849 _EGLDriver *
850 _eglMain(_EGLDisplay *dpy)
851 {
852 fbDriver *fb;
853
854 fb = (fbDriver *) calloc(1, sizeof(fbDriver));
855 if (!fb) {
856 return NULL;
857 }
858
859 /* First fill in the dispatch table with defaults */
860 _eglInitDriverFallbacks(&fb->Base);
861
862 /* then plug in our fb-specific functions */
863 fb->Base.Initialize = fbInitialize;
864 fb->Base.Terminate = fbTerminate;
865 fb->Base.CreateContext = fbCreateContext;
866 fb->Base.MakeCurrent = fbMakeCurrent;
867 fb->Base.CreateWindowSurface = fbCreateWindowSurface;
868 fb->Base.CreatePixmapSurface = fbCreatePixmapSurface;
869 fb->Base.CreatePbufferSurface = fbCreatePbufferSurface;
870 fb->Base.DestroySurface = fbDestroySurface;
871 fb->Base.DestroyContext = fbDestroyContext;
872 fb->Base.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
873 fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
874 fb->Base.SwapBuffers = fbSwapBuffers;
875
876 /* enable supported extensions */
877 fb->Base.MESA_screen_surface = EGL_TRUE;
878 fb->Base.MESA_copy_context = EGL_TRUE;
879
880 return &fb->Base;
881 }