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