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)
106 /* do not handle this signal when cleaning up */
107 signal(SIGWINCH
, SIG_IGN
);
119 glutDestroyWindow(1);
121 /* restore original variable screen info */
122 if(FrameBufferFD
!= -1) {
123 OrigVarInfo
.xoffset
= 0;
124 OrigVarInfo
.yoffset
= 0;
126 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
127 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
130 munmap(FrameBuffer
, FixedInfo
.smem_len
);
131 close(FrameBufferFD
);
134 /* free allocated back buffer */
135 if(DisplayMode
& GLUT_DOUBLE
)
138 /* free menu items */
142 fprintf(stderr
, "[glfbdev glut] %s", exiterror
);
145 static void CrashHandler(int sig
)
147 sprintf(exiterror
, "Caught signal %d, cleaning up\n", sig
);
151 static void removeArgs(int *argcp
, char **argv
, int num
)
154 for (i
= 0; argv
[i
+num
]; i
++)
155 argv
[i
] = argv
[i
+num
];
161 #define REQPARAM(PARAM) \
162 if (i >= *argcp - 1) { \
163 fprintf(stderr, PARAM" requires a parameter\n"); \
167 void glutInit (int *argcp
, char **argv
)
169 int i
, nomouse
= 0, nokeyboard
= 0, usestdin
= 0;
170 int RequiredWidth
= 0, RequiredHeight
;
174 for (i
= 1; i
< *argcp
;) {
175 if (!strcmp(argv
[i
], "-geometry")) {
176 REQPARAM("geometry");
177 if(sscanf(argv
[i
+1], "%dx%d", &RequiredWidth
,
178 &RequiredHeight
) != 2) {
179 fprintf(stderr
,"Please specify geometry as widthxheight\n");
182 removeArgs(argcp
, &argv
[i
], 2);
184 if (!strcmp(argv
[i
], "-bpp")) {
186 if(sscanf(argv
[i
+1], "%d", &DesiredDepth
) != 1) {
187 fprintf(stderr
, "Please specify a parameter for bpp\n");
190 removeArgs(argcp
, &argv
[i
], 2);
192 if (!strcmp(argv
[i
], "-vt")) {
194 if(sscanf(argv
[i
+1], "%d", &CurrentVT
) != 1) {
195 fprintf(stderr
, "Please specify a parameter for vt\n");
198 removeArgs(argcp
, &argv
[i
], 2);
200 if (!strcmp(argv
[i
], "-mousespeed")) {
201 REQPARAM("mousespeed");
202 if(sscanf(argv
[i
+1], "%lf", &MouseSpeed
) != 1) {
203 fprintf(stderr
, "Please specify a mouse speed, eg: 2.5\n");
206 removeArgs(argcp
, &argv
[i
], 2);
208 if (!strcmp(argv
[i
], "-nomouse")) {
210 removeArgs(argcp
, &argv
[i
], 1);
212 if (!strcmp(argv
[i
], "-nokeyboard")) {
214 removeArgs(argcp
, &argv
[i
], 1);
216 if (!strcmp(argv
[i
], "-stdin")) {
218 removeArgs(argcp
, &argv
[i
], 1);
220 if (!strcmp(argv
[i
], "-gpmmouse")) {
224 fprintf(stderr
, "gpm support not compiled\n");
227 removeArgs(argcp
, &argv
[i
], 1);
229 if (!strcmp(argv
[i
], "--")) {
230 removeArgs(argcp
, &argv
[i
], 1);
236 gettimeofday(&StartTime
, 0);
239 signal(SIGSEGV
, CrashHandler
);
240 signal(SIGINT
, CrashHandler
);
241 signal(SIGTERM
, CrashHandler
);
242 signal(SIGABRT
, CrashHandler
);
247 InitializeVT(usestdin
);
249 fbdev
= getenv("FRAMEBUFFER");
252 if(!sscanf(fbdev
, "/dev/fb%d", &FramebufferIndex
))
253 if(!sscanf(fbdev
, "/dev/fb/%d", &FramebufferIndex
))
254 sprintf(exiterror
, "Could not determine Framebuffer index!\n");
258 struct fb_con2fbmap confb
;
259 int fd
= open("/dev/fb0", O_RDWR
);
261 FramebufferIndex
= 0;
263 confb
.console
= CurrentVT
;
264 if(ioctl(fd
, FBIOGET_CON2FBMAP
, &confb
) != -1)
265 FramebufferIndex
= confb
.framebuffer
;
266 sprintf(fb
, "/dev/fb%d", FramebufferIndex
);
271 /* open the framebuffer device */
272 FrameBufferFD
= open(fbdev
, O_RDWR
);
273 if (FrameBufferFD
< 0) {
274 sprintf(exiterror
, "Error opening %s: %s\n", fbdev
, strerror(errno
));
278 /* get the fixed screen info */
279 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
280 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
285 /* get the variable screen info */
286 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &OrigVarInfo
)) {
287 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
292 /* operate on a copy */
293 VarInfo
= OrigVarInfo
;
295 /* set the depth, resolution, etc */
297 if(!ParseFBModes(RequiredWidth
, RequiredWidth
, RequiredHeight
,
298 RequiredHeight
, 0, MAX_VSYNC
)) {
299 sprintf(exiterror
, "No mode (%dx%d) found in "FBMODES
"\n",
300 RequiredWidth
, RequiredHeight
);
307 void glutInitDisplayMode (unsigned int mode
)
312 static const char *GetStrVal(const char *p
, int *set
, int min
, int max
)
323 val
= strtol(p
+1, &endptr
, 10);
343 if(val
< min
|| val
> max
) {
344 sprintf(exiterror
, "display string value out of range\n");
353 static void SetAttrib(int val
, int attr
)
358 DisplayMode
&= ~attr
;
361 void glutInitDisplayString(const char *string
)
363 const char *p
= string
;
369 if(memcmp(p
, "acca", 4) == 0) {
370 p
= GetStrVal(p
+4, &AccumSize
, 1, 32);
371 SetAttrib(AccumSize
, GLUT_ACCUM
);
373 if(memcmp(p
, "acc", 3) == 0) {
374 p
= GetStrVal(p
+3, &AccumSize
, 1, 32);
375 SetAttrib(AccumSize
, GLUT_ACCUM
);
377 if(memcmp(p
, "depth", 5) == 0) {
378 p
= GetStrVal(p
+5, &DepthSize
, 12, 32);
379 SetAttrib(DepthSize
, GLUT_DEPTH
);
381 if(memcmp(p
, "double", 6) == 0) {
383 p
= GetStrVal(p
+6, &val
, 0, 1);
384 SetAttrib(val
, GLUT_DOUBLE
);
386 if(memcmp(p
, "index", 5) == 0) {
388 p
= GetStrVal(p
+5, &val
, 0, 1);
389 SetAttrib(val
, GLUT_INDEX
);
391 if(memcmp(p
, "stencil", 7) == 0) {
392 p
= GetStrVal(p
+7, &StencilSize
, 0, 1);
393 SetAttrib(StencilSize
, GLUT_STENCIL
);
395 if(memcmp(p
, "samples", 7) == 0) {
397 p
= GetStrVal(p
+7, &NumSamples
, 0, 16);
398 SetAttrib(NumSamples
, GLUT_MULTISAMPLE
);
400 if(p
= strchr(p
, ' '))
407 void glutInitWindowPosition (int x
, int y
)
411 void glutInitWindowSize (int width
, int height
)
415 static void ProcessTimers(void)
417 while(GlutTimers
&& GlutTimers
->time
<= glutGet(GLUT_ELAPSED_TIME
)) {
418 struct GlutTimer
*timer
= GlutTimers
;
419 GlutTimers
= timer
->next
;
420 timer
->func(timer
->value
);
425 void glutMainLoop(void)
428 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
431 sprintf(exiterror
, "Fatal Error: No Display Function registered\n");
452 VisibilityFunc(Visible
? GLUT_VISIBLE
: GLUT_NOT_VISIBLE
);
455 if(Visible
&& Redisplay
) {
460 if(!(DisplayMode
& GLUT_DOUBLE
)) {
470 int ParseFBModes(int minw
, int maxw
, int minh
, int maxh
, int minf
, int maxf
)
473 struct fb_var_screeninfo vi
= VarInfo
;
475 FILE *fbmodes
= fopen(FBMODES
, "r");
478 sprintf(exiterror
, "Warning: could not open "FBMODES
"\n");
482 while(fgets(buf
, sizeof buf
, fbmodes
)) {
486 if(!(c
= strstr(buf
, "geometry")))
488 v
= sscanf(c
, "geometry %d %d %d %d %d", &vi
.xres
, &vi
.yres
,
489 &vi
.xres_virtual
, &vi
.yres_virtual
, &bpp
);
494 if(maxw
< vi
.xres
&& minw
> vi
.xres
)
497 if(maxw
< vi
.xres
|| minw
> vi
.xres
)
501 if(maxh
< vi
.yres
&& minh
> vi
.yres
)
504 if(maxh
< vi
.yres
|| minh
> vi
.yres
)
507 fgets(buf
, sizeof buf
, fbmodes
);
508 if(!(c
= strstr(buf
, "timings")))
511 v
= sscanf(c
, "timings %d %d %d %d %d %d %d", &vi
.pixclock
,
512 &vi
.left_margin
, &vi
.right_margin
, &vi
.upper_margin
,
513 &vi
.lower_margin
, &vi
.hsync_len
, &vi
.vsync_len
);
518 freq
= 1E12
/vi
.pixclock
519 /(vi
.left_margin
+ vi
.xres
+ vi
.right_margin
+ vi
.hsync_len
)
520 /(vi
.upper_margin
+ vi
.yres
+ vi
.lower_margin
+ vi
.vsync_len
);
523 if(maxf
< freq
&& minf
> freq
)
526 if(maxf
< freq
|| minf
> freq
)
539 /* ---------- Window Management ----------*/
540 void SetVideoMode(void)
542 /* set new variable screen info */
543 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
544 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
549 /* reload the screen info to update offsets */
550 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &VarInfo
)) {
551 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
556 /* reload the fixed info to update color mode */
557 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
558 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
563 if (DesiredDepth
&& DesiredDepth
!= VarInfo
.bits_per_pixel
) {
564 sprintf(exiterror
, "error: Could not set set %d bpp\n", DesiredDepth
);
568 if(DisplayMode
& GLUT_INDEX
&& FixedInfo
.visual
== FB_VISUAL_DIRECTCOLOR
) {
569 sprintf(exiterror
, "error: Could not set 8 bit color mode\n");
573 /* initialize colormap */
579 int size
= VarInfo
.xres_virtual
* VarInfo
.yres_virtual
580 * VarInfo
.bits_per_pixel
/ 8;
582 /* mmap the framebuffer into our address space */
584 munmap(FrameBuffer
, FixedInfo
.smem_len
);
585 FrameBuffer
= mmap(0, FixedInfo
.smem_len
, PROT_READ
| PROT_WRITE
,
586 MAP_SHARED
, FrameBufferFD
, 0);
587 if (FrameBuffer
== MAP_FAILED
) {
588 sprintf(exiterror
, "error: unable to mmap framebuffer: %s\n",
593 if(DisplayMode
& GLUT_DOUBLE
) {
595 if(!(BackBuffer
= malloc(size
))) {
596 sprintf(exiterror
, "Failed to allocate double buffer\n");
600 BackBuffer
= FrameBuffer
;
603 glFBDevDestroyBuffer(Buffer
);
605 if(!(Buffer
= glFBDevCreateBuffer( &FixedInfo
, &VarInfo
, Visual
,
606 FrameBuffer
, BackBuffer
, size
))) {
607 sprintf(exiterror
, "Failure to create Buffer\n");
612 void CreateVisual(void)
614 int i
, mask
= DisplayMode
;
616 for(i
=0; i
<sizeof(attribs
)/sizeof(*attribs
) && mask
; i
++) {
617 if(mask
& GLUT_DOUBLE
) {
618 attribs
[i
] = GLFBDEV_DOUBLE_BUFFER
;
619 mask
&= ~GLUT_DOUBLE
;
623 if(mask
& GLUT_INDEX
) {
624 attribs
[i
] = GLFBDEV_COLOR_INDEX
;
629 if(mask
& GLUT_DEPTH
) {
630 attribs
[i
] = GLFBDEV_DEPTH_SIZE
;
631 attribs
[++i
] = DepthSize
;
636 if(mask
& GLUT_STENCIL
) {
637 attribs
[i
] = GLFBDEV_STENCIL_SIZE
;
638 attribs
[++i
] = StencilSize
;
639 mask
&= ~GLUT_STENCIL
;
643 if(mask
& GLUT_ACCUM
) {
644 attribs
[i
] = GLFBDEV_ACCUM_SIZE
;
645 attribs
[++i
] = AccumSize
;
650 if(mask
& GLUT_ALPHA
)
651 if(!(DisplayMode
& GLUT_INDEX
)) {
657 if(mask
& GLUT_MULTISAMPLE
) {
658 attribs
[i
] = GLFBDEV_MULTISAMPLE
;
659 attribs
[++i
] = NumSamples
;
660 mask
&= ~GLUT_MULTISAMPLE
;
664 sprintf(exiterror
, "Invalid mode from glutInitDisplayMode\n");
668 attribs
[i
] = GLFBDEV_NONE
;
670 if(!(Visual
= glFBDevCreateVisual( &FixedInfo
, &VarInfo
, attribs
))) {
671 sprintf(exiterror
, "Failure to create Visual\n");
676 static void ResizeVisual(void)
678 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
679 sprintf(exiterror
, "Failure to Make Current\n");
686 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
690 static void SignalWinch(int arg
)
692 /* we can't change bitdepth without destroying the visual */
693 int bits_per_pixel
= VarInfo
.bits_per_pixel
;
694 struct fb_bitfield red
= VarInfo
.red
, green
= VarInfo
.green
,
695 blue
= VarInfo
.blue
, transp
= VarInfo
.transp
;
697 /* get the variable screen info */
698 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &VarInfo
)) {
699 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
704 /* restore bitdepth and color masks only */
705 VarInfo
.bits_per_pixel
= bits_per_pixel
;
707 VarInfo
.green
= green
;
709 VarInfo
.transp
= transp
;
717 int glutCreateWindow (const char *title
)
719 if(Initialized
== 0) {
721 char *argv
[] = {NULL
};
722 glutInit(&argc
, argv
);
728 if(DisplayMode
& GLUT_INDEX
)
729 VarInfo
.bits_per_pixel
= 8;
731 if(VarInfo
.bits_per_pixel
== 8)
732 VarInfo
.bits_per_pixel
= 32;
735 VarInfo
.bits_per_pixel
= DesiredDepth
;
740 VarInfo
.vmode
&= ~FB_VMODE_YWRAP
; /* turn off scrolling */
746 if(!(Context
= glFBDevCreateContext(Visual
, NULL
))) {
747 sprintf(exiterror
, "Failure to create Context\n");
751 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
752 sprintf(exiterror
, "Failure to Make Current\n");
759 glutSetWindowTitle(title
);
761 signal(SIGWINCH
, SignalWinch
);
769 int glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
774 void glutSetWindow(int win
)
778 int glutGetWindow(void)
783 void glutDestroyWindow(int win
)
785 glFBDevMakeCurrent( NULL
, NULL
, NULL
);
786 glFBDevDestroyContext(Context
);
787 glFBDevDestroyBuffer(Buffer
);
788 glFBDevDestroyVisual(Visual
);
792 void glutPostRedisplay(void)
797 void glutPostWindowRedisplay(int win
)
802 void glutSwapBuffers(void)
811 if(DisplayMode
& GLUT_DOUBLE
&& Visible
) {
813 glFBDevSwapBuffers(Buffer
);
817 /* if there was a vt switch while swapping, switch now */
819 if(ioctl(ConsoleFD
, VT_ACTIVATE
, VTSwitch
) < 0)
820 sprintf(exiterror
, "Error switching console\n");
825 void glutPositionWindow(int x
, int y
)
829 void glutReshapeWindow(int width
, int height
)
834 if(!ParseFBModes(width
, width
, height
, height
, 0, MAX_VSYNC
))
837 signal(SIGWINCH
, SIG_IGN
);
843 signal(SIGWINCH
, SignalWinch
);
846 void glutFullScreen(void)
850 void glutPopWindow(void)
854 void glutPushWindow(void)
858 void glutShowWindow(void)
863 void glutHideWindow(void)
868 static void UnIconifyWindow(int sig
)
875 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
876 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
888 void glutIconifyWindow(void)
891 signal(SIGCONT
, UnIconifyWindow
);
892 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
893 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
899 void glutSetWindowTitle(const char *name
)
901 /* escape code to set title in screen */
902 if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
903 printf("\033k%s\033\\", name
);
906 void glutSetIconTitle(const char *name
)