implement arb_vertex_program in hw for r200. Code contains still some hacks, generic...
[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 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 _ac_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->ResizeBuffers = _mesa_resize_framebuffer;
433 functions->GetBufferSize = get_buffer_size;
434 functions->Viewport = viewport;
435
436 functions->Clear = _swrast_Clear; /* could accelerate with blits */
437 }
438
439
440 static EGLContext
441 fbCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
442 {
443 GLcontext *ctx;
444 _EGLConfig *conf;
445 fbContext *c;
446 _EGLDisplay *disp = _eglLookupDisplay(dpy);
447 struct dd_function_table functions;
448 GLvisual vis;
449 int i;
450
451 conf = _eglLookupConfig(drv, dpy, config);
452 if (!conf) {
453 _eglError(EGL_BAD_CONFIG, "eglCreateContext");
454 return EGL_NO_CONTEXT;
455 }
456
457 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
458 switch (attrib_list[i]) {
459 /* no attribs defined for now */
460 default:
461 _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
462 return EGL_NO_CONTEXT;
463 }
464 }
465
466 c = (fbContext *) calloc(1, sizeof(fbContext));
467 if (!c)
468 return EGL_NO_CONTEXT;
469
470 _eglInitContext(&c->Base);
471 c->Base.Display = disp;
472 c->Base.Config = conf;
473 c->Base.DrawSurface = EGL_NO_SURFACE;
474 c->Base.ReadSurface = EGL_NO_SURFACE;
475
476 /* generate handle and insert into hash table */
477 _eglSaveContext(&c->Base);
478 assert(c->Base.Handle);
479
480 /* Init default driver functions then plug in our FBdev-specific functions
481 */
482 _mesa_init_driver_functions(&functions);
483 init_core_functions(&functions);
484
485 _eglConfigToContextModesRec(conf, &vis);
486
487 ctx = c->glCtx = _mesa_create_context(&vis, NULL, &functions, (void *)c);
488 if (!c->glCtx) {
489 _mesa_free(c);
490 return GL_FALSE;
491 }
492
493 /* Create module contexts */
494 _swrast_CreateContext( ctx );
495 _ac_CreateContext( ctx );
496 _tnl_CreateContext( ctx );
497 _swsetup_CreateContext( ctx );
498 _swsetup_Wakeup( ctx );
499
500
501 /* use default TCL pipeline */
502 {
503 TNLcontext *tnl = TNL_CONTEXT(ctx);
504 tnl->Driver.RunPipeline = _tnl_run_pipeline;
505 }
506
507 _mesa_enable_sw_extensions(ctx);
508
509 return c->Base.Handle;
510 }
511
512
513 static EGLSurface
514 fbCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
515 {
516 int i;
517 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
518 switch (attrib_list[i]) {
519 /* no attribs at this time */
520 default:
521 _eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface");
522 return EGL_NO_SURFACE;
523 }
524 }
525 printf("eglCreateWindowSurface()\n");
526 /* XXX unfinished */
527
528 return EGL_NO_SURFACE;
529 }
530
531
532 static EGLSurface
533 fbCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
534 {
535 _EGLConfig *conf;
536 EGLint i;
537
538 conf = _eglLookupConfig(drv, dpy, config);
539 if (!conf) {
540 _eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface");
541 return EGL_NO_SURFACE;
542 }
543
544 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
545 switch (attrib_list[i]) {
546 /* no attribs at this time */
547 default:
548 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
549 return EGL_NO_SURFACE;
550 }
551 }
552
553 if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) {
554 _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface");
555 return EGL_NO_SURFACE;
556 }
557
558 printf("eglCreatePixmapSurface()\n");
559 return EGL_NO_SURFACE;
560 }
561
562
563 static EGLSurface
564 fbCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
565 {
566 fbSurface *surf;
567
568 surf = (fbSurface *) calloc(1, sizeof(fbSurface));
569 if (!surf) {
570 return EGL_NO_SURFACE;
571 }
572
573 if (_eglInitPbufferSurface(&surf->Base, drv, dpy, config, attrib_list) == EGL_NO_SURFACE) {
574 free(surf);
575 return EGL_NO_SURFACE;
576 }
577
578 /* create software-based pbuffer */
579 {
580 GLcontext *ctx = NULL; /* this _should_ be OK */
581 GLvisual vis;
582 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
583 assert(conf); /* bad config should be caught earlier */
584 _eglConfigToContextModesRec(conf, &vis);
585
586 surf->mesa_framebuffer = _mesa_create_framebuffer(&vis);
587 _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
588 GL_TRUE, /* color bufs */
589 vis.haveDepthBuffer,
590 vis.haveStencilBuffer,
591 vis.haveAccumBuffer,
592 GL_FALSE, /* alpha */
593 GL_FALSE /* aux */ );
594
595 /* set pbuffer/framebuffer size */
596 _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
597 surf->Base.Width, surf->Base.Height);
598 }
599
600 return surf->Base.Handle;
601 }
602
603
604 static EGLBoolean
605 fbDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
606 {
607 fbSurface *fs = Lookup_fbSurface(surface);
608 _eglRemoveSurface(&fs->Base);
609 if (fs->Base.IsBound) {
610 fs->Base.DeletePending = EGL_TRUE;
611 }
612 else {
613 free(fs);
614 }
615 return EGL_TRUE;
616 }
617
618
619 static EGLBoolean
620 fbDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
621 {
622 fbContext *fc = Lookup_fbContext(context);
623 _eglRemoveContext(&fc->Base);
624 if (fc->Base.IsBound) {
625 fc->Base.DeletePending = EGL_TRUE;
626 }
627 else {
628 free(fc);
629 }
630 return EGL_TRUE;
631 }
632
633
634 static EGLBoolean
635 fbMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
636 {
637 fbSurface *readSurf = Lookup_fbSurface(read);
638 fbSurface *drawSurf = Lookup_fbSurface(draw);
639 fbContext *ctx = Lookup_fbContext(context);
640 EGLBoolean b;
641
642 b = _eglMakeCurrent(drv, dpy, draw, read, context);
643 if (!b)
644 return EGL_FALSE;
645
646 if (ctx) {
647 _mesa_make_current( ctx->glCtx,
648 drawSurf->mesa_framebuffer,
649 readSurf->mesa_framebuffer);
650 } else
651 _mesa_make_current( NULL, NULL, NULL );
652
653 return EGL_TRUE;
654 }
655
656
657 /**
658 * Create a drawing surface which can be directly displayed on a screen.
659 */
660 static EGLSurface
661 fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
662 const EGLint *attrib_list)
663 {
664 _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
665 fbDisplay *display = Lookup_fbDisplay(dpy);
666 fbSurface *surface;
667 EGLSurface surf;
668 GLvisual vis;
669 GLcontext *ctx = NULL; /* this should be OK */
670 int origin, bytesPerPixel;
671 int width, height, stride;
672
673 surface = (fbSurface *) malloc(sizeof(*surface));
674 if (!surface) {
675 return EGL_NO_SURFACE;
676 }
677
678 /* init base class, error check, etc. */
679 surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list);
680 if (surf == EGL_NO_SURFACE) {
681 free(surface);
682 return EGL_NO_SURFACE;
683 }
684
685 /* convert EGLConfig to GLvisual */
686 _eglConfigToContextModesRec(config, &vis);
687
688 /* create Mesa framebuffer */
689 surface->mesa_framebuffer = _mesa_create_framebuffer(&vis);
690 if (!surface->mesa_framebuffer) {
691 free(surface);
692 _eglRemoveSurface(&surface->Base);
693 return EGL_NO_SURFACE;
694 }
695
696 width = surface->Base.Width;
697 height = surface->Base.Height;
698 bytesPerPixel = vis.rgbBits / 8;
699 stride = width * bytesPerPixel;
700 origin = 0;
701
702 /* front color renderbuffer */
703 {
704 driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, display->pFB,
705 bytesPerPixel,
706 origin, stride, NULL);
707 fbSetSpanFunctions(drb, &vis);
708 _mesa_add_renderbuffer(surface->mesa_framebuffer,
709 BUFFER_FRONT_LEFT, &drb->Base);
710 }
711
712 /* back color renderbuffer */
713 if (vis.doubleBufferMode) {
714 GLubyte *backBuf = _mesa_malloc(stride * height);
715 driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, backBuf,
716 bytesPerPixel,
717 origin, stride, NULL);
718 fbSetSpanFunctions(drb, &vis);
719 _mesa_add_renderbuffer(surface->mesa_framebuffer,
720 BUFFER_BACK_LEFT, &drb->Base);
721 }
722
723 /* other renderbuffers- software based */
724 _mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
725 GL_FALSE, /* color */
726 vis.haveDepthBuffer,
727 vis.haveStencilBuffer,
728 vis.haveAccumBuffer,
729 GL_FALSE, /* alpha */
730 GL_FALSE /* aux */);
731
732 _mesa_resize_framebuffer(ctx, surface->mesa_framebuffer, width, height);
733
734 return surf;
735 }
736
737
738 /**
739 * Show the given surface on the named screen.
740 * If surface is EGL_NO_SURFACE, disable the screen's output.
741 */
742 static EGLBoolean
743 fbShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
744 EGLSurface surface, EGLModeMESA m)
745 {
746 fbDisplay *display = Lookup_fbDisplay(dpy);
747 fbScreen *scrn = Lookup_fbScreen(dpy, screen);
748 fbSurface *surf = Lookup_fbSurface(surface);
749 FILE *file;
750 char buffer[NAME_MAX];
751 _EGLMode *mode = _eglLookupMode(dpy, m);
752 int bits;
753
754 if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
755 return EGL_FALSE;
756
757 snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
758
759 file = fopen(buffer, "r+");
760 if (!file) {
761 err:
762 printf("chown all fb sysfs attrib to allow write - %s\n", buffer);
763 return EGL_FALSE;
764 }
765 snprintf(buffer, sizeof(buffer), "%d", (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
766 fputs(buffer, file);
767 fclose(file);
768
769 if (m == EGL_NO_MODE_MESA)
770 return EGL_TRUE;
771
772 snprintf(buffer, sizeof(buffer), "%s/%s/mode", sysfs, scrn->fb);
773
774 file = fopen(buffer, "r+");
775 if (!file)
776 goto err;
777 fputs(mode->Name, file);
778 fclose(file);
779
780 snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
781
782 file = fopen(buffer, "r+");
783 if (!file)
784 goto err;
785 bits = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
786 snprintf(buffer, sizeof(buffer), "%d", bits);
787 fputs(buffer, file);
788 fclose(file);
789
790 fbSetupFramebuffer(display, scrn->fb);
791
792 snprintf(buffer, sizeof(buffer), "%s/%s/blank", sysfs, scrn->fb);
793
794 file = fopen(buffer, "r+");
795 if (!file)
796 goto err;
797
798 snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
799 fputs(buffer, file);
800 fclose(file);
801
802 return EGL_TRUE;
803 }
804
805
806 /* If the backbuffer is on a videocard, this is extraordinarily slow!
807 */
808 static EGLBoolean
809 fbSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
810 {
811 fbContext *context = (fbContext *)_eglGetCurrentContext();
812 fbSurface *fs = Lookup_fbSurface(draw);
813 struct gl_renderbuffer * front_renderbuffer = fs->mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
814 void *frontBuffer = front_renderbuffer->Data;
815 int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch;
816 void *backBuffer = fs->mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data;
817
818 if (!_eglSwapBuffers(drv, dpy, draw))
819 return EGL_FALSE;
820
821 if (context) {
822 GLcontext *ctx = context->glCtx;
823
824 if (ctx->Visual.doubleBufferMode) {
825 int i;
826 int offset = 0;
827 char *tmp = _mesa_malloc(currentPitch);
828
829 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
830
831 ASSERT(frontBuffer);
832 ASSERT(backBuffer);
833
834 for (i = 0; i < fs->Base.Height; i++) {
835 _mesa_memcpy(tmp, (char *) backBuffer + offset,
836 currentPitch);
837 _mesa_memcpy((char *) frontBuffer + offset, tmp,
838 currentPitch);
839 offset += currentPitch;
840 }
841
842 _mesa_free(tmp);
843 }
844 }
845 else {
846 /* XXX this shouldn't be an error but we can't handle it for now */
847 _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n");
848 return EGL_FALSE;
849 }
850 return EGL_TRUE;
851 }
852
853
854 /**
855 * The bootstrap function. Return a new fbDriver object and
856 * plug in API functions.
857 */
858 _EGLDriver *
859 _eglMain(_EGLDisplay *dpy)
860 {
861 fbDriver *fb;
862
863 fb = (fbDriver *) calloc(1, sizeof(fbDriver));
864 if (!fb) {
865 return NULL;
866 }
867
868 /* First fill in the dispatch table with defaults */
869 _eglInitDriverFallbacks(&fb->Base);
870
871 /* then plug in our fb-specific functions */
872 fb->Base.Initialize = fbInitialize;
873 fb->Base.Terminate = fbTerminate;
874 fb->Base.CreateContext = fbCreateContext;
875 fb->Base.MakeCurrent = fbMakeCurrent;
876 fb->Base.CreateWindowSurface = fbCreateWindowSurface;
877 fb->Base.CreatePixmapSurface = fbCreatePixmapSurface;
878 fb->Base.CreatePbufferSurface = fbCreatePbufferSurface;
879 fb->Base.DestroySurface = fbDestroySurface;
880 fb->Base.DestroyContext = fbDestroyContext;
881 fb->Base.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
882 fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
883 fb->Base.SwapBuffers = fbSwapBuffers;
884
885 /* enable supported extensions */
886 fb->Base.MESA_screen_surface = EGL_TRUE;
887 fb->Base.MESA_copy_context = EGL_TRUE;
888
889 return &fb->Base;
890 }