2 * Mesa 3-D graphics library
4 * Copyright (C) 1995-2006 Brian Paul
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Library for glut using mesa fbdev driver
24 * Written by Sean D'Epagnier (c) 2006
26 * To improve on this library, maybe support subwindows or overlays,
27 * I (sean at depagnier dot com) will do my best to help.
51 #define FBMODES "/etc/fb.modes"
53 struct fb_fix_screeninfo FixedInfo
;
54 struct fb_var_screeninfo VarInfo
;
55 static struct fb_var_screeninfo OrigVarInfo
;
57 static int DesiredDepth
= 0;
59 int FrameBufferFD
= -1;
60 unsigned char *FrameBuffer
;
61 unsigned char *BackBuffer
= NULL
;
64 struct GlutTimer
*GlutTimers
= NULL
;
66 struct timeval StartTime
;
69 GLFBDevContextPtr Context
;
70 GLFBDevBufferPtr Buffer
;
71 GLFBDevVisualPtr Visual
;
77 /* we have to poll to see if we are visible
78 on a framebuffer that is not active */
80 int Swapping
, VTSwitch
;
81 static int FramebufferIndex
;
83 static int Initialized
;
87 /* test if the active console is attached to the same framebuffer */
88 void TestVisible(void) {
89 struct fb_con2fbmap confb
;
92 ioctl(ConsoleFD
, VT_GETSTATE
, &st
);
93 confb
.console
= st
.v_active
;
95 ret
= ioctl(FrameBufferFD
, FBIOGET_CON2FBMAP
, &confb
);
97 if(ret
== -1 || confb
.framebuffer
== FramebufferIndex
) {
104 static void Cleanup(void)
116 glutDestroyWindow(1);
118 /* restore original variable screen info */
119 if(FrameBufferFD
!= -1) {
120 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
121 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
124 munmap(FrameBuffer
, FixedInfo
.smem_len
);
125 close(FrameBufferFD
);
128 /* free allocated back buffer */
129 if(DisplayMode
& GLUT_DOUBLE
)
132 /* free menu items */
136 fprintf(stderr
, "[glfbdev glut] %s", exiterror
);
139 static void CrashHandler(int sig
)
141 sprintf(exiterror
, "Caught signal %d, cleaning up\n", sig
);
145 static void removeArgs(int *argcp
, char **argv
, int num
)
148 for (i
= 0; argv
[i
+num
]; i
++)
149 argv
[i
] = argv
[i
+num
];
155 #define REQPARAM(PARAM) \
156 if (i >= *argcp - 1) { \
157 fprintf(stderr, PARAM" requires a parameter\n"); \
161 void glutInit (int *argcp
, char **argv
)
163 int i
, nomouse
= 0, nokeyboard
= 0, usestdin
= 0;
164 int RequiredWidth
= 0, RequiredHeight
;
168 for (i
= 1; i
< *argcp
;) {
169 if (!strcmp(argv
[i
], "-geometry")) {
170 REQPARAM("geometry");
171 if(sscanf(argv
[i
+1], "%dx%d", &RequiredWidth
,
172 &RequiredHeight
) != 2) {
173 fprintf(stderr
,"Please specify geometry as widthxheight\n");
176 removeArgs(argcp
, &argv
[i
], 2);
178 if (!strcmp(argv
[i
], "-bpp")) {
180 if(sscanf(argv
[i
+1], "%d", &DesiredDepth
) != 1) {
181 fprintf(stderr
, "Please specify a parameter for bpp\n");
184 removeArgs(argcp
, &argv
[i
], 2);
186 if (!strcmp(argv
[i
], "-vt")) {
188 if(sscanf(argv
[i
+1], "%d", &CurrentVT
) != 1) {
189 fprintf(stderr
, "Please specify a parameter for vt\n");
192 removeArgs(argcp
, &argv
[i
], 2);
194 if (!strcmp(argv
[i
], "-mousespeed")) {
195 REQPARAM("mousespeed");
196 if(sscanf(argv
[i
+1], "%lf", &MouseSpeed
) != 1) {
197 fprintf(stderr
, "Please specify a mouse speed, eg: 2.5\n");
200 removeArgs(argcp
, &argv
[i
], 2);
202 if (!strcmp(argv
[i
], "-nomouse")) {
204 removeArgs(argcp
, &argv
[i
], 1);
206 if (!strcmp(argv
[i
], "-nokeyboard")) {
208 removeArgs(argcp
, &argv
[i
], 1);
210 if (!strcmp(argv
[i
], "-stdin")) {
212 removeArgs(argcp
, &argv
[i
], 1);
214 if (!strcmp(argv
[i
], "-gpmmouse")) {
218 fprintf(stderr
, "gpm support not compiled\n");
221 removeArgs(argcp
, &argv
[i
], 1);
223 if (!strcmp(argv
[i
], "--")) {
224 removeArgs(argcp
, &argv
[i
], 1);
230 gettimeofday(&StartTime
, 0);
233 signal(SIGSEGV
, CrashHandler
);
234 signal(SIGINT
, CrashHandler
);
235 signal(SIGTERM
, CrashHandler
);
240 InitializeVT(usestdin
);
242 fbdev
= getenv("FRAMEBUFFER");
245 if(!sscanf(fbdev
, "/dev/fb%d", &FramebufferIndex
))
246 if(!sscanf(fbdev
, "/dev/fb/%d", &FramebufferIndex
))
247 sprintf(exiterror
, "Could not determine Framebuffer index!\n");
251 struct fb_con2fbmap confb
;
252 int fd
= open("/dev/fb0", O_RDWR
);
254 FramebufferIndex
= 0;
256 confb
.console
= CurrentVT
;
257 if(ioctl(fd
, FBIOGET_CON2FBMAP
, &confb
) != -1)
258 FramebufferIndex
= confb
.framebuffer
;
259 sprintf(fb
, "/dev/fb%d", FramebufferIndex
);
264 /* open the framebuffer device */
265 FrameBufferFD
= open(fbdev
, O_RDWR
);
266 if (FrameBufferFD
< 0) {
267 sprintf(exiterror
, "Error opening %s: %s\n", fbdev
, strerror(errno
));
271 /* Get the fixed screen info */
272 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
273 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
278 /* get the variable screen info */
279 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &OrigVarInfo
)) {
280 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
285 /* operate on a copy */
286 VarInfo
= OrigVarInfo
;
288 /* set the depth, resolution, etc */
290 if(!ParseFBModes(RequiredWidth
, RequiredWidth
, RequiredHeight
,
291 RequiredHeight
, 0, MAX_VSYNC
)) {
292 sprintf(exiterror
, "No mode (%dx%d) found in "FBMODES
"\n",
293 RequiredWidth
, RequiredHeight
);
300 void glutInitDisplayMode (unsigned int mode
)
305 static const char *GetStrVal(const char *p
, int *set
, int min
, int max
)
316 val
= strtol(p
+1, &endptr
, 10);
336 if(val
< min
|| val
> max
) {
337 sprintf(exiterror
, "display string value out of range\n");
346 static void SetAttrib(int val
, int attr
)
351 DisplayMode
&= ~attr
;
354 void glutInitDisplayString(const char *string
)
356 const char *p
= string
;
362 if(memcmp(p
, "acca", 4) == 0) {
363 p
= GetStrVal(p
+4, &AccumSize
, 1, 32);
364 SetAttrib(AccumSize
, GLUT_ACCUM
);
366 if(memcmp(p
, "acc", 3) == 0) {
367 p
= GetStrVal(p
+3, &AccumSize
, 1, 32);
368 SetAttrib(AccumSize
, GLUT_ACCUM
);
370 if(memcmp(p
, "depth", 5) == 0) {
371 p
= GetStrVal(p
+5, &DepthSize
, 12, 32);
372 SetAttrib(DepthSize
, GLUT_DEPTH
);
374 if(memcmp(p
, "double", 6) == 0) {
376 p
= GetStrVal(p
+6, &val
, 0, 1);
377 SetAttrib(val
, GLUT_DOUBLE
);
379 if(memcmp(p
, "index", 5) == 0) {
381 p
= GetStrVal(p
+5, &val
, 0, 1);
382 SetAttrib(val
, GLUT_INDEX
);
384 if(memcmp(p
, "stencil", 7) == 0) {
385 p
= GetStrVal(p
+7, &StencilSize
, 0, 1);
386 SetAttrib(StencilSize
, GLUT_STENCIL
);
388 if(memcmp(p
, "samples", 7) == 0) {
390 p
= GetStrVal(p
+7, &NumSamples
, 0, 16);
391 SetAttrib(NumSamples
, GLUT_MULTISAMPLE
);
393 if(p
= strchr(p
, ' '))
400 void glutInitWindowPosition (int x
, int y
)
404 void glutInitWindowSize (int width
, int height
)
408 static void ProcessTimers(void)
410 if(GlutTimers
&& GlutTimers
->time
< glutGet(GLUT_ELAPSED_TIME
)) {
411 struct GlutTimer
*timer
= GlutTimers
;
412 timer
->func(timer
->value
);
413 GlutTimers
= timer
->next
;
418 void glutMainLoop(void)
421 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
424 sprintf(exiterror
, "Fatal Error: No Display Function registered\n");
445 VisibilityFunc(Visible
? GLUT_VISIBLE
: GLUT_NOT_VISIBLE
);
448 if(Visible
&& Redisplay
) {
453 if(!(DisplayMode
& GLUT_DOUBLE
)) {
463 int ParseFBModes(int minw
, int maxw
, int minh
, int maxh
, int minf
, int maxf
)
466 struct fb_var_screeninfo vi
= VarInfo
;
468 FILE *fbmodes
= fopen(FBMODES
, "r");
471 sprintf(exiterror
, "Warning: could not open "FBMODES
"\n");
475 while(fgets(buf
, sizeof buf
, fbmodes
)) {
479 if(!(c
= strstr(buf
, "geometry")))
481 v
= sscanf(c
, "geometry %d %d %d %d %d", &vi
.xres
, &vi
.yres
,
482 &vi
.xres_virtual
, &vi
.yres_virtual
, &bpp
);
487 if(maxw
< vi
.xres
&& minw
> vi
.xres
)
490 if(maxw
< vi
.xres
|| minw
> vi
.xres
)
494 if(maxh
< vi
.yres
&& minh
> vi
.yres
)
497 if(maxh
< vi
.yres
|| minh
> vi
.yres
)
500 fgets(buf
, sizeof buf
, fbmodes
);
501 if(!(c
= strstr(buf
, "timings")))
504 v
= sscanf(c
, "timings %d %d %d %d %d %d %d", &vi
.pixclock
,
505 &vi
.left_margin
, &vi
.right_margin
, &vi
.upper_margin
,
506 &vi
.lower_margin
, &vi
.hsync_len
, &vi
.vsync_len
);
511 freq
= 1E12
/vi
.pixclock
512 /(vi
.left_margin
+ vi
.xres
+ vi
.right_margin
+ vi
.hsync_len
)
513 /(vi
.upper_margin
+ vi
.yres
+ vi
.lower_margin
+ vi
.vsync_len
);
516 if(maxf
< freq
&& minf
> freq
)
519 if(maxf
< freq
|| minf
> freq
)
532 /* ---------- Window Management ----------*/
533 void SetVideoMode(void)
535 /* set new variable screen info */
536 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
537 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
542 /* reload the screen info to update offsets */
543 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &VarInfo
)) {
544 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
549 /* reload the fixed info to update color mode */
550 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
551 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
556 if (DesiredDepth
&& DesiredDepth
!= VarInfo
.bits_per_pixel
) {
557 sprintf(exiterror
, "error: Could not set set %d bpp\n", DesiredDepth
);
561 if(DisplayMode
& GLUT_INDEX
&& FixedInfo
.visual
== FB_VISUAL_DIRECTCOLOR
) {
562 sprintf(exiterror
, "error: Could not set 8 bit color mode\n");
566 /* initialize colormap */
572 int size
= VarInfo
.xres_virtual
* VarInfo
.yres_virtual
573 * VarInfo
.bits_per_pixel
/ 8;
575 /* mmap the framebuffer into our address space */
577 munmap(FrameBuffer
, FixedInfo
.smem_len
);
578 FrameBuffer
= mmap(0, FixedInfo
.smem_len
, PROT_READ
| PROT_WRITE
,
579 MAP_SHARED
, FrameBufferFD
, 0);
580 if (FrameBuffer
== MAP_FAILED
) {
581 sprintf(exiterror
, "error: unable to mmap framebuffer: %s\n",
586 if(DisplayMode
& GLUT_DOUBLE
) {
588 if(!(BackBuffer
= malloc(size
))) {
589 sprintf(exiterror
, "Failed to allocate double buffer\n");
593 BackBuffer
= FrameBuffer
;
596 glFBDevDestroyBuffer(Buffer
);
598 if(!(Buffer
= glFBDevCreateBuffer( &FixedInfo
, &VarInfo
, Visual
,
599 FrameBuffer
, BackBuffer
, size
))) {
600 sprintf(exiterror
, "Failure to create Buffer\n");
605 void CreateVisual(void)
607 int i
, mask
= DisplayMode
;
609 for(i
=0; i
<sizeof(attribs
)/sizeof(*attribs
) && mask
; i
++) {
610 if(mask
& GLUT_DOUBLE
) {
611 attribs
[i
] = GLFBDEV_DOUBLE_BUFFER
;
612 mask
&= ~GLUT_DOUBLE
;
616 if(mask
& GLUT_INDEX
) {
617 attribs
[i
] = GLFBDEV_COLOR_INDEX
;
622 if(mask
& GLUT_DEPTH
) {
623 attribs
[i
] = GLFBDEV_DEPTH_SIZE
;
624 attribs
[++i
] = DepthSize
;
629 if(mask
& GLUT_STENCIL
) {
630 attribs
[i
] = GLFBDEV_STENCIL_SIZE
;
631 attribs
[++i
] = StencilSize
;
632 mask
&= ~GLUT_STENCIL
;
636 if(mask
& GLUT_ACCUM
) {
637 attribs
[i
] = GLFBDEV_ACCUM_SIZE
;
638 attribs
[++i
] = AccumSize
;
643 if(mask
& GLUT_ALPHA
)
644 if(!(DisplayMode
& GLUT_INDEX
)) {
650 if(mask
& GLUT_MULTISAMPLE
) {
651 attribs
[i
] = GLFBDEV_MULTISAMPLE
;
652 attribs
[++i
] = NumSamples
;
653 mask
&= ~GLUT_MULTISAMPLE
;
657 sprintf(exiterror
, "Invalid mode from glutInitDisplayMode\n");
661 attribs
[i
] = GLFBDEV_NONE
;
663 if(!(Visual
= glFBDevCreateVisual( &FixedInfo
, &VarInfo
, attribs
))) {
664 sprintf(exiterror
, "Failure to create Visual\n");
669 int glutCreateWindow (const char *title
)
671 if(Initialized
== 0) {
673 char *argv
[] = {NULL
};
674 glutInit(&argc
, argv
);
680 if(DisplayMode
& GLUT_INDEX
)
681 VarInfo
.bits_per_pixel
= 8;
683 if(VarInfo
.bits_per_pixel
== 8)
684 VarInfo
.bits_per_pixel
= 32;
687 VarInfo
.bits_per_pixel
= DesiredDepth
;
692 VarInfo
.vmode
&= ~FB_VMODE_YWRAP
; /* turn off scrolling */
698 if(!(Context
= glFBDevCreateContext(Visual
, NULL
))) {
699 sprintf(exiterror
, "Failure to create Context\n");
703 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
704 sprintf(exiterror
, "Failure to Make Current\n");
711 glutSetWindowTitle(title
);
719 int glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
724 void glutSetWindow(int win
)
728 int glutGetWindow(void)
733 void glutDestroyWindow(int win
)
735 glFBDevMakeCurrent( NULL
, NULL
, NULL
);
736 glFBDevDestroyContext(Context
);
737 glFBDevDestroyBuffer(Buffer
);
738 glFBDevDestroyVisual(Visual
);
742 void glutPostRedisplay(void)
747 void glutPostWindowRedisplay(int win
)
752 void glutSwapBuffers(void)
761 if(DisplayMode
& GLUT_DOUBLE
&& Visible
) {
763 glFBDevSwapBuffers(Buffer
);
767 /* if there was a vt switch while swapping, switch now */
769 if(ioctl(ConsoleFD
, VT_ACTIVATE
, VTSwitch
) < 0)
770 sprintf(exiterror
, "Error switching console\n");
775 void glutPositionWindow(int x
, int y
)
779 void glutReshapeWindow(int width
, int height
)
784 if(!ParseFBModes(width
, width
, height
, height
, 0, MAX_VSYNC
))
790 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
791 sprintf(exiterror
, "Failure to Make Current\n");
798 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
802 void glutFullScreen(void)
806 void glutPopWindow(void)
810 void glutPushWindow(void)
814 void glutShowWindow(void)
819 void glutHideWindow(void)
824 static void UnIconifyWindow(int sig
)
831 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
832 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
841 void glutIconifyWindow(void)
844 signal(SIGCONT
, UnIconifyWindow
);
845 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
846 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
851 void glutSetWindowTitle(const char *name
)
853 /* escape code to set title in screen */
854 if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
855 printf("\033k%s\033\\", name
);
858 void glutSetIconTitle(const char *name
)