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