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 OrigVarInfo
.xoffset
= 0;
121 OrigVarInfo
.yoffset
= 0;
123 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
124 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
127 munmap(FrameBuffer
, FixedInfo
.smem_len
);
128 close(FrameBufferFD
);
131 /* free allocated back buffer */
132 if(DisplayMode
& GLUT_DOUBLE
)
135 /* free menu items */
139 fprintf(stderr
, "[glfbdev glut] %s", exiterror
);
142 static void CrashHandler(int sig
)
144 sprintf(exiterror
, "Caught signal %d, cleaning up\n", sig
);
148 static void removeArgs(int *argcp
, char **argv
, int num
)
151 for (i
= 0; argv
[i
+num
]; i
++)
152 argv
[i
] = argv
[i
+num
];
158 #define REQPARAM(PARAM) \
159 if (i >= *argcp - 1) { \
160 fprintf(stderr, PARAM" requires a parameter\n"); \
164 void glutInit (int *argcp
, char **argv
)
166 int i
, nomouse
= 0, nokeyboard
= 0, usestdin
= 0;
167 int RequiredWidth
= 0, RequiredHeight
;
171 for (i
= 1; i
< *argcp
;) {
172 if (!strcmp(argv
[i
], "-geometry")) {
173 REQPARAM("geometry");
174 if(sscanf(argv
[i
+1], "%dx%d", &RequiredWidth
,
175 &RequiredHeight
) != 2) {
176 fprintf(stderr
,"Please specify geometry as widthxheight\n");
179 removeArgs(argcp
, &argv
[i
], 2);
181 if (!strcmp(argv
[i
], "-bpp")) {
183 if(sscanf(argv
[i
+1], "%d", &DesiredDepth
) != 1) {
184 fprintf(stderr
, "Please specify a parameter for bpp\n");
187 removeArgs(argcp
, &argv
[i
], 2);
189 if (!strcmp(argv
[i
], "-vt")) {
191 if(sscanf(argv
[i
+1], "%d", &CurrentVT
) != 1) {
192 fprintf(stderr
, "Please specify a parameter for vt\n");
195 removeArgs(argcp
, &argv
[i
], 2);
197 if (!strcmp(argv
[i
], "-mousespeed")) {
198 REQPARAM("mousespeed");
199 if(sscanf(argv
[i
+1], "%lf", &MouseSpeed
) != 1) {
200 fprintf(stderr
, "Please specify a mouse speed, eg: 2.5\n");
203 removeArgs(argcp
, &argv
[i
], 2);
205 if (!strcmp(argv
[i
], "-nomouse")) {
207 removeArgs(argcp
, &argv
[i
], 1);
209 if (!strcmp(argv
[i
], "-nokeyboard")) {
211 removeArgs(argcp
, &argv
[i
], 1);
213 if (!strcmp(argv
[i
], "-stdin")) {
215 removeArgs(argcp
, &argv
[i
], 1);
217 if (!strcmp(argv
[i
], "-gpmmouse")) {
221 fprintf(stderr
, "gpm support not compiled\n");
224 removeArgs(argcp
, &argv
[i
], 1);
226 if (!strcmp(argv
[i
], "--")) {
227 removeArgs(argcp
, &argv
[i
], 1);
233 gettimeofday(&StartTime
, 0);
236 signal(SIGSEGV
, CrashHandler
);
237 signal(SIGINT
, CrashHandler
);
238 signal(SIGTERM
, CrashHandler
);
243 InitializeVT(usestdin
);
245 fbdev
= getenv("FRAMEBUFFER");
248 if(!sscanf(fbdev
, "/dev/fb%d", &FramebufferIndex
))
249 if(!sscanf(fbdev
, "/dev/fb/%d", &FramebufferIndex
))
250 sprintf(exiterror
, "Could not determine Framebuffer index!\n");
254 struct fb_con2fbmap confb
;
255 int fd
= open("/dev/fb0", O_RDWR
);
257 FramebufferIndex
= 0;
259 confb
.console
= CurrentVT
;
260 if(ioctl(fd
, FBIOGET_CON2FBMAP
, &confb
) != -1)
261 FramebufferIndex
= confb
.framebuffer
;
262 sprintf(fb
, "/dev/fb%d", FramebufferIndex
);
267 /* open the framebuffer device */
268 FrameBufferFD
= open(fbdev
, O_RDWR
);
269 if (FrameBufferFD
< 0) {
270 sprintf(exiterror
, "Error opening %s: %s\n", fbdev
, strerror(errno
));
274 /* Get the fixed screen info */
275 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
276 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
281 /* get the variable screen info */
282 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &OrigVarInfo
)) {
283 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
288 /* operate on a copy */
289 VarInfo
= OrigVarInfo
;
291 /* set the depth, resolution, etc */
293 if(!ParseFBModes(RequiredWidth
, RequiredWidth
, RequiredHeight
,
294 RequiredHeight
, 0, MAX_VSYNC
)) {
295 sprintf(exiterror
, "No mode (%dx%d) found in "FBMODES
"\n",
296 RequiredWidth
, RequiredHeight
);
303 void glutInitDisplayMode (unsigned int mode
)
308 static const char *GetStrVal(const char *p
, int *set
, int min
, int max
)
319 val
= strtol(p
+1, &endptr
, 10);
339 if(val
< min
|| val
> max
) {
340 sprintf(exiterror
, "display string value out of range\n");
349 static void SetAttrib(int val
, int attr
)
354 DisplayMode
&= ~attr
;
357 void glutInitDisplayString(const char *string
)
359 const char *p
= string
;
365 if(memcmp(p
, "acca", 4) == 0) {
366 p
= GetStrVal(p
+4, &AccumSize
, 1, 32);
367 SetAttrib(AccumSize
, GLUT_ACCUM
);
369 if(memcmp(p
, "acc", 3) == 0) {
370 p
= GetStrVal(p
+3, &AccumSize
, 1, 32);
371 SetAttrib(AccumSize
, GLUT_ACCUM
);
373 if(memcmp(p
, "depth", 5) == 0) {
374 p
= GetStrVal(p
+5, &DepthSize
, 12, 32);
375 SetAttrib(DepthSize
, GLUT_DEPTH
);
377 if(memcmp(p
, "double", 6) == 0) {
379 p
= GetStrVal(p
+6, &val
, 0, 1);
380 SetAttrib(val
, GLUT_DOUBLE
);
382 if(memcmp(p
, "index", 5) == 0) {
384 p
= GetStrVal(p
+5, &val
, 0, 1);
385 SetAttrib(val
, GLUT_INDEX
);
387 if(memcmp(p
, "stencil", 7) == 0) {
388 p
= GetStrVal(p
+7, &StencilSize
, 0, 1);
389 SetAttrib(StencilSize
, GLUT_STENCIL
);
391 if(memcmp(p
, "samples", 7) == 0) {
393 p
= GetStrVal(p
+7, &NumSamples
, 0, 16);
394 SetAttrib(NumSamples
, GLUT_MULTISAMPLE
);
396 if(p
= strchr(p
, ' '))
403 void glutInitWindowPosition (int x
, int y
)
407 void glutInitWindowSize (int width
, int height
)
411 static void ProcessTimers(void)
413 if(GlutTimers
&& GlutTimers
->time
< glutGet(GLUT_ELAPSED_TIME
)) {
414 struct GlutTimer
*timer
= GlutTimers
;
415 timer
->func(timer
->value
);
416 GlutTimers
= timer
->next
;
421 void glutMainLoop(void)
424 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
427 sprintf(exiterror
, "Fatal Error: No Display Function registered\n");
448 VisibilityFunc(Visible
? GLUT_VISIBLE
: GLUT_NOT_VISIBLE
);
451 if(Visible
&& Redisplay
) {
456 if(!(DisplayMode
& GLUT_DOUBLE
)) {
466 int ParseFBModes(int minw
, int maxw
, int minh
, int maxh
, int minf
, int maxf
)
469 struct fb_var_screeninfo vi
= VarInfo
;
471 FILE *fbmodes
= fopen(FBMODES
, "r");
474 sprintf(exiterror
, "Warning: could not open "FBMODES
"\n");
478 while(fgets(buf
, sizeof buf
, fbmodes
)) {
482 if(!(c
= strstr(buf
, "geometry")))
484 v
= sscanf(c
, "geometry %d %d %d %d %d", &vi
.xres
, &vi
.yres
,
485 &vi
.xres_virtual
, &vi
.yres_virtual
, &bpp
);
490 if(maxw
< vi
.xres
&& minw
> vi
.xres
)
493 if(maxw
< vi
.xres
|| minw
> vi
.xres
)
497 if(maxh
< vi
.yres
&& minh
> vi
.yres
)
500 if(maxh
< vi
.yres
|| minh
> vi
.yres
)
503 fgets(buf
, sizeof buf
, fbmodes
);
504 if(!(c
= strstr(buf
, "timings")))
507 v
= sscanf(c
, "timings %d %d %d %d %d %d %d", &vi
.pixclock
,
508 &vi
.left_margin
, &vi
.right_margin
, &vi
.upper_margin
,
509 &vi
.lower_margin
, &vi
.hsync_len
, &vi
.vsync_len
);
514 freq
= 1E12
/vi
.pixclock
515 /(vi
.left_margin
+ vi
.xres
+ vi
.right_margin
+ vi
.hsync_len
)
516 /(vi
.upper_margin
+ vi
.yres
+ vi
.lower_margin
+ vi
.vsync_len
);
519 if(maxf
< freq
&& minf
> freq
)
522 if(maxf
< freq
|| minf
> freq
)
535 /* ---------- Window Management ----------*/
536 void SetVideoMode(void)
538 /* set new variable screen info */
539 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
540 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
545 /* reload the screen info to update offsets */
546 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &VarInfo
)) {
547 sprintf(exiterror
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
552 /* reload the fixed info to update color mode */
553 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
554 sprintf(exiterror
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
559 if (DesiredDepth
&& DesiredDepth
!= VarInfo
.bits_per_pixel
) {
560 sprintf(exiterror
, "error: Could not set set %d bpp\n", DesiredDepth
);
564 if(DisplayMode
& GLUT_INDEX
&& FixedInfo
.visual
== FB_VISUAL_DIRECTCOLOR
) {
565 sprintf(exiterror
, "error: Could not set 8 bit color mode\n");
569 /* initialize colormap */
575 int size
= VarInfo
.xres_virtual
* VarInfo
.yres_virtual
576 * VarInfo
.bits_per_pixel
/ 8;
578 /* mmap the framebuffer into our address space */
580 munmap(FrameBuffer
, FixedInfo
.smem_len
);
581 FrameBuffer
= mmap(0, FixedInfo
.smem_len
, PROT_READ
| PROT_WRITE
,
582 MAP_SHARED
, FrameBufferFD
, 0);
583 if (FrameBuffer
== MAP_FAILED
) {
584 sprintf(exiterror
, "error: unable to mmap framebuffer: %s\n",
589 if(DisplayMode
& GLUT_DOUBLE
) {
591 if(!(BackBuffer
= malloc(size
))) {
592 sprintf(exiterror
, "Failed to allocate double buffer\n");
596 BackBuffer
= FrameBuffer
;
599 glFBDevDestroyBuffer(Buffer
);
601 if(!(Buffer
= glFBDevCreateBuffer( &FixedInfo
, &VarInfo
, Visual
,
602 FrameBuffer
, BackBuffer
, size
))) {
603 sprintf(exiterror
, "Failure to create Buffer\n");
608 void CreateVisual(void)
610 int i
, mask
= DisplayMode
;
612 for(i
=0; i
<sizeof(attribs
)/sizeof(*attribs
) && mask
; i
++) {
613 if(mask
& GLUT_DOUBLE
) {
614 attribs
[i
] = GLFBDEV_DOUBLE_BUFFER
;
615 mask
&= ~GLUT_DOUBLE
;
619 if(mask
& GLUT_INDEX
) {
620 attribs
[i
] = GLFBDEV_COLOR_INDEX
;
625 if(mask
& GLUT_DEPTH
) {
626 attribs
[i
] = GLFBDEV_DEPTH_SIZE
;
627 attribs
[++i
] = DepthSize
;
632 if(mask
& GLUT_STENCIL
) {
633 attribs
[i
] = GLFBDEV_STENCIL_SIZE
;
634 attribs
[++i
] = StencilSize
;
635 mask
&= ~GLUT_STENCIL
;
639 if(mask
& GLUT_ACCUM
) {
640 attribs
[i
] = GLFBDEV_ACCUM_SIZE
;
641 attribs
[++i
] = AccumSize
;
646 if(mask
& GLUT_ALPHA
)
647 if(!(DisplayMode
& GLUT_INDEX
)) {
653 if(mask
& GLUT_MULTISAMPLE
) {
654 attribs
[i
] = GLFBDEV_MULTISAMPLE
;
655 attribs
[++i
] = NumSamples
;
656 mask
&= ~GLUT_MULTISAMPLE
;
660 sprintf(exiterror
, "Invalid mode from glutInitDisplayMode\n");
664 attribs
[i
] = GLFBDEV_NONE
;
666 if(!(Visual
= glFBDevCreateVisual( &FixedInfo
, &VarInfo
, attribs
))) {
667 sprintf(exiterror
, "Failure to create Visual\n");
672 int glutCreateWindow (const char *title
)
674 if(Initialized
== 0) {
676 char *argv
[] = {NULL
};
677 glutInit(&argc
, argv
);
683 if(DisplayMode
& GLUT_INDEX
)
684 VarInfo
.bits_per_pixel
= 8;
686 if(VarInfo
.bits_per_pixel
== 8)
687 VarInfo
.bits_per_pixel
= 32;
690 VarInfo
.bits_per_pixel
= DesiredDepth
;
695 VarInfo
.vmode
&= ~FB_VMODE_YWRAP
; /* turn off scrolling */
701 if(!(Context
= glFBDevCreateContext(Visual
, NULL
))) {
702 sprintf(exiterror
, "Failure to create Context\n");
706 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
707 sprintf(exiterror
, "Failure to Make Current\n");
714 glutSetWindowTitle(title
);
722 int glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
727 void glutSetWindow(int win
)
731 int glutGetWindow(void)
736 void glutDestroyWindow(int win
)
738 glFBDevMakeCurrent( NULL
, NULL
, NULL
);
739 glFBDevDestroyContext(Context
);
740 glFBDevDestroyBuffer(Buffer
);
741 glFBDevDestroyVisual(Visual
);
745 void glutPostRedisplay(void)
750 void glutPostWindowRedisplay(int win
)
755 void glutSwapBuffers(void)
764 if(DisplayMode
& GLUT_DOUBLE
&& Visible
) {
766 glFBDevSwapBuffers(Buffer
);
770 /* if there was a vt switch while swapping, switch now */
772 if(ioctl(ConsoleFD
, VT_ACTIVATE
, VTSwitch
) < 0)
773 sprintf(exiterror
, "Error switching console\n");
778 void glutPositionWindow(int x
, int y
)
782 void glutReshapeWindow(int width
, int height
)
787 if(!ParseFBModes(width
, width
, height
, height
, 0, MAX_VSYNC
))
793 if(!glFBDevMakeCurrent( Context
, Buffer
, Buffer
)) {
794 sprintf(exiterror
, "Failure to Make Current\n");
801 ReshapeFunc(VarInfo
.xres
, VarInfo
.yres
);
805 void glutFullScreen(void)
809 void glutPopWindow(void)
813 void glutPushWindow(void)
817 void glutShowWindow(void)
822 void glutHideWindow(void)
827 static void UnIconifyWindow(int sig
)
834 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
835 sprintf(exiterror
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
844 void glutIconifyWindow(void)
847 signal(SIGCONT
, UnIconifyWindow
);
848 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
))
849 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
854 void glutSetWindowTitle(const char *name
)
856 /* escape code to set title in screen */
857 if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
858 printf("\033k%s\033\\", name
);
861 void glutSetIconTitle(const char *name
)