summaryrefslogtreecommitdiff
path: root/src/glut/fbdev/fbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glut/fbdev/fbdev.c')
-rw-r--r--src/glut/fbdev/fbdev.c465
1 files changed, 312 insertions, 153 deletions
diff --git a/src/glut/fbdev/fbdev.c b/src/glut/fbdev/fbdev.c
index fcbd4f8da2..ce7d187b66 100644
--- a/src/glut/fbdev/fbdev.c
+++ b/src/glut/fbdev/fbdev.c
@@ -22,6 +22,9 @@
* Library for glut using mesa fbdev driver
*
* Written by Sean D'Epagnier (c) 2006
+ *
+ * To improve on this library, maybe support subwindows or overlays,
+ * I (sean at depagnier dot com) will do my best to help.
*/
#include <errno.h>
@@ -41,16 +44,15 @@
#include <linux/vt.h>
#include <GL/gl.h>
-#include <GL/glfbdev.h>
#include <GL/glut.h>
#include "internal.h"
#define FBMODES "/etc/fb.modes"
-
struct fb_fix_screeninfo FixedInfo;
-struct fb_var_screeninfo VarInfo, OrigVarInfo;
+struct fb_var_screeninfo VarInfo;
+static struct fb_var_screeninfo OrigVarInfo;
static int DesiredDepth = 0;
@@ -64,9 +66,9 @@ struct GlutTimer *GlutTimers = NULL;
struct timeval StartTime;
/* per window data */
-static GLFBDevContextPtr Context;
-static GLFBDevBufferPtr Buffer;
-static GLFBDevVisualPtr Visual;
+GLFBDevContextPtr Context;
+GLFBDevBufferPtr Buffer;
+GLFBDevVisualPtr Visual;
int Redisplay;
int Visible;
@@ -75,13 +77,9 @@ int Active;
/* we have to poll to see if we are visible
on a framebuffer that is not active */
int VisiblePoll;
+int Swapping, VTSwitch;
static int FramebufferIndex;
-static int RequiredWidth;
-static int RequiredHeight;
-static int InitialWidthHint;
-static int InitialHeightHint;
-
static int Initialized;
char exiterror[256];
@@ -105,6 +103,9 @@ void TestVisible(void) {
static void Cleanup(void)
{
+ if(GameMode)
+ glutLeaveGameMode();
+
if(ConsoleFD != -1)
RestoreVT();
@@ -136,7 +137,7 @@ static void Cleanup(void)
if(exiterror[0])
fprintf(stderr, "[glfbdev glut] %s", exiterror);
-}
+ }
static void CrashHandler(int sig)
{
@@ -162,10 +163,9 @@ static void removeArgs(int *argcp, char **argv, int num)
void glutInit (int *argcp, char **argv)
{
- int i;
- int nomouse = 0;
- int nokeyboard = 0;
- int usestdin = 0;
+ int i, nomouse = 0, nokeyboard = 0, usestdin = 0;
+ int RequiredWidth = 0, RequiredHeight;
+ char *fbdev;
/* parse out args */
for (i = 1; i < *argcp;) {
@@ -242,6 +242,61 @@ void glutInit (int *argcp, char **argv)
if(nokeyboard == 0)
InitializeVT(usestdin);
+ fbdev = getenv("FRAMEBUFFER");
+ if(fbdev) {
+#ifdef MULTIHEAD
+ if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
+ if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
+ sprintf(exiterror, "Could not determine Framebuffer index!\n");
+#endif
+ } else {
+ static char fb[128];
+ struct fb_con2fbmap confb;
+ int fd = open("/dev/fb0", O_RDWR);
+
+ FramebufferIndex = 0;
+
+ confb.console = CurrentVT;
+ if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
+ FramebufferIndex = confb.framebuffer;
+ sprintf(fb, "/dev/fb%d", FramebufferIndex);
+ fbdev = fb;
+ close(fd);
+ }
+
+ /* open the framebuffer device */
+ FrameBufferFD = open(fbdev, O_RDWR);
+ if (FrameBufferFD < 0) {
+ sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
+ exit(0);
+ }
+
+ /* Get the fixed screen info */
+ if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
+ sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+ strerror(errno));
+ exit(0);
+ }
+
+ /* get the variable screen info */
+ if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
+ sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ exit(0);
+ }
+
+ /* operate on a copy */
+ VarInfo = OrigVarInfo;
+
+ /* set the depth, resolution, etc */
+ if(RequiredWidth)
+ if(!ParseFBModes(RequiredWidth, RequiredWidth, RequiredHeight,
+ RequiredHeight, 0, MAX_VSYNC)) {
+ sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
+ RequiredWidth, RequiredHeight);
+ exit(0);
+ }
+
Initialized = 1;
}
@@ -250,17 +305,109 @@ void glutInitDisplayMode (unsigned int mode)
DisplayMode = mode;
}
+static const char *GetStrVal(const char *p, int *set, int min, int max)
+{
+ char *endptr;
+ int comp = *p, val;
+
+ if(p[1] == '=')
+ p++;
+
+ if(*p == '\0')
+ return p;
+
+ val = strtol(p+1, &endptr, 10);
+
+ if(endptr == p+1)
+ return p;
+
+ switch(comp) {
+ case '!':
+ if(val == min)
+ val = max;
+ else
+ val = min;
+ break;
+ case '<':
+ val = min;
+ break;
+ case '>':
+ val = max;
+ break;
+ }
+
+ if(val < min || val > max) {
+ sprintf(exiterror, "display string value out of range\n");
+ exit(0);
+ }
+
+ *set = val;
+
+ return endptr;
+}
+
+static void SetAttrib(int val, int attr)
+{
+ if(val)
+ DisplayMode |= attr;
+ else
+ DisplayMode &= ~attr;
+}
+
+void glutInitDisplayString(const char *string)
+{
+ const char *p = string;
+ int val;
+ while(*p) {
+ if(*p == ' ')
+ p++;
+ else
+ if(memcmp(p, "acca", 4) == 0) {
+ p = GetStrVal(p+4, &AccumSize, 1, 32);
+ SetAttrib(AccumSize, GLUT_ACCUM);
+ } else
+ if(memcmp(p, "acc", 3) == 0) {
+ p = GetStrVal(p+3, &AccumSize, 1, 32);
+ SetAttrib(AccumSize, GLUT_ACCUM);
+ } else
+ if(memcmp(p, "depth", 5) == 0) {
+ p = GetStrVal(p+5, &DepthSize, 12, 32);
+ SetAttrib(DepthSize, GLUT_DEPTH);
+ } else
+ if(memcmp(p, "double", 6) == 0) {
+ val = 1;
+ p = GetStrVal(p+6, &val, 0, 1);
+ SetAttrib(val, GLUT_DOUBLE);
+ } else
+ if(memcmp(p, "index", 5) == 0) {
+ val = 1;
+ p = GetStrVal(p+5, &val, 0, 1);
+ SetAttrib(val, GLUT_INDEX);
+ } else
+ if(memcmp(p, "stencil", 7) == 0) {
+ p = GetStrVal(p+7, &StencilSize, 0, 1);
+ SetAttrib(StencilSize, GLUT_STENCIL);
+ } else
+ if(memcmp(p, "samples", 7) == 0) {
+ NumSamples = 1;
+ p = GetStrVal(p+7, &NumSamples, 0, 16);
+ SetAttrib(NumSamples, GLUT_MULTISAMPLE);
+ } else
+ if(p = strchr(p, ' '))
+ p++;
+ else
+ break;
+ }
+}
+
void glutInitWindowPosition (int x, int y)
{
}
void glutInitWindowSize (int width, int height)
{
- InitialWidthHint = width;
- InitialHeightHint = height;
}
-
static void ProcessTimers(void)
{
if(GlutTimers && GlutTimers->time < glutGet(GLUT_ELAPSED_TIME)) {
@@ -289,10 +436,12 @@ void glutMainLoop(void)
else
if(VisiblePoll)
TestVisible();
+ else
+ usleep(1);
if(IdleFunc)
IdleFunc();
-
+
if(VisibleSwitch) {
VisibleSwitch = 0;
if(VisibilityFunc)
@@ -314,7 +463,7 @@ void glutMainLoop(void)
}
}
-static void ParseFBModes(void)
+int ParseFBModes(int minw, int maxw, int minh, int maxh, int minf, int maxf)
{
char buf[1024];
struct fb_var_screeninfo vi = VarInfo;
@@ -322,44 +471,34 @@ static void ParseFBModes(void)
FILE *fbmodes = fopen(FBMODES, "r");
if(!fbmodes) {
- sprintf(exiterror, "Warning: could not open "
- FBMODES" using current mode\n");
- return;
+ sprintf(exiterror, "Warning: could not open "FBMODES"\n");
+ return 0;
}
- if(InitialWidthHint == 0 && InitialHeightHint == 0
- && RequiredWidth == 0)
- return; /* use current mode */
-
while(fgets(buf, sizeof buf, fbmodes)) {
char *c;
- int v;
+ int v, bpp, freq;
if(!(c = strstr(buf, "geometry")))
continue;
v = sscanf(c, "geometry %d %d %d %d %d", &vi.xres, &vi.yres,
- &vi.xres_virtual, &vi.yres_virtual, &vi.bits_per_pixel);
+ &vi.xres_virtual, &vi.yres_virtual, &bpp);
if(v != 5)
continue;
- /* now we have to decide what is best */
- if(RequiredWidth) {
- if(RequiredWidth != vi.xres || RequiredHeight != vi.yres)
+ if(maxw < minw) {
+ if(maxw < vi.xres && minw > vi.xres)
continue;
- } else {
- if(VarInfo.xres < vi.xres && VarInfo.xres < InitialWidthHint)
- v++;
- if(VarInfo.xres > vi.xres && vi.xres > InitialWidthHint)
- v++;
-
- if(VarInfo.yres < vi.yres && VarInfo.yres < InitialHeightHint)
- v++;
- if(VarInfo.yres > vi.yres && vi.yres > InitialHeightHint)
- v++;
-
- if(v < 7)
+ } else
+ if(maxw < vi.xres || minw > vi.xres)
+ continue;
+
+ if(maxh < minh) {
+ if(maxh < vi.yres && minh > vi.yres)
+ continue;
+ } else
+ if(maxh < vi.yres || minh > vi.yres)
continue;
- }
fgets(buf, sizeof buf, fbmodes);
if(!(c = strstr(buf, "timings")))
@@ -368,103 +507,34 @@ static void ParseFBModes(void)
v = sscanf(c, "timings %d %d %d %d %d %d %d", &vi.pixclock,
&vi.left_margin, &vi.right_margin, &vi.upper_margin,
&vi.lower_margin, &vi.hsync_len, &vi.vsync_len);
+
if(v != 7)
continue;
- VarInfo = vi; /* finally found a better mode */
- if(RequiredWidth) {
- fclose(fbmodes);
- return;
- }
+ freq = 1E12/vi.pixclock
+ /(vi.left_margin + vi.xres + vi.right_margin + vi.hsync_len)
+ /(vi.upper_margin + vi.yres + vi.lower_margin + vi.vsync_len);
+
+ if(maxf < minf) {
+ if(maxf < freq && minf > freq)
+ continue;
+ } else
+ if(maxf < freq || minf > freq)
+ continue;
+
+ VarInfo = vi;
+ fclose(fbmodes);
+ return 1;
}
fclose(fbmodes);
- if(RequiredWidth) {
- sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
- RequiredWidth, RequiredHeight);
- exit(0);
- }
+ return 0;
}
/* ---------- Window Management ----------*/
-int glutCreateWindow (const char *title)
+void SetVideoMode(void)
{
- char *fbdev;
- int attribs[9], i, mask, size;
-
- if(Initialized == 0) {
- int argc = 0;
- char *argv[] = {NULL};
- glutInit(&argc, argv);
- }
-
- if(Context)
- return 0;
-
- fbdev = getenv("FRAMEBUFFER");
- if(fbdev) {
-#ifdef MULTIHEAD
- if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
- if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
- sprintf(exiterror, "Could not determine Framebuffer index!\n");
-#endif
- } else {
- static char fb[128];
- struct fb_con2fbmap confb;
- int fd = open("/dev/fb0", O_RDWR);
-
- FramebufferIndex = 0;
-
- confb.console = CurrentVT;
- if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
- FramebufferIndex = confb.framebuffer;
- sprintf(fb, "/dev/fb%d", FramebufferIndex);
- fbdev = fb;
- close(fd);
- }
-
- /* open the framebuffer device */
- FrameBufferFD = open(fbdev, O_RDWR);
- if (FrameBufferFD < 0) {
- sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
- exit(0);
- }
-
- /* Get the fixed screen info */
- if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
- sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
- strerror(errno));
- exit(0);
- }
-
- /* get the variable screen info */
- if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
- sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
- strerror(errno));
- exit(0);
- }
-
- /* operate on a copy */
- VarInfo = OrigVarInfo;
-
- /* set the depth, resolution, etc */
- ParseFBModes();
-
- if(DisplayMode & GLUT_INDEX)
- VarInfo.bits_per_pixel = 8;
- else
- if(VarInfo.bits_per_pixel == 8)
- VarInfo.bits_per_pixel = 32;
-
- if (DesiredDepth)
- VarInfo.bits_per_pixel = DesiredDepth;
-
- VarInfo.xoffset = 0;
- VarInfo.yoffset = 0;
- VarInfo.nonstd = 0;
- VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
-
/* set new variable screen info */
if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
sprintf(exiterror, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
@@ -498,8 +568,16 @@ int glutCreateWindow (const char *title)
/* initialize colormap */
LoadColorMap();
+}
+
+void CreateBuffer()
+{
+ int size = VarInfo.xres_virtual * VarInfo.yres_virtual
+ * VarInfo.bits_per_pixel / 8;
/* mmap the framebuffer into our address space */
+ if(FrameBuffer)
+ munmap(FrameBuffer, FixedInfo.smem_len);
FrameBuffer = mmap(0, FixedInfo.smem_len, PROT_READ | PROT_WRITE,
MAP_SHARED, FrameBufferFD, 0);
if (FrameBuffer == MAP_FAILED) {
@@ -508,8 +586,30 @@ int glutCreateWindow (const char *title)
exit(0);
}
- mask = DisplayMode;
- for(i=0; i<8 && mask; i++) {
+ if(DisplayMode & GLUT_DOUBLE) {
+ free(BackBuffer);
+ if(!(BackBuffer = malloc(size))) {
+ sprintf(exiterror, "Failed to allocate double buffer\n");
+ exit(0);
+ }
+ } else
+ BackBuffer = FrameBuffer;
+
+ if(Buffer)
+ glFBDevDestroyBuffer(Buffer);
+
+ if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
+ FrameBuffer, BackBuffer, size))) {
+ sprintf(exiterror, "Failure to create Buffer\n");
+ exit(0);
+ }
+}
+
+void CreateVisual(void)
+{
+ int i, mask = DisplayMode;
+ int attribs[20];
+ for(i=0; i<sizeof(attribs)/sizeof(*attribs) && mask; i++) {
if(mask & GLUT_DOUBLE) {
attribs[i] = GLFBDEV_DOUBLE_BUFFER;
mask &= ~GLUT_DOUBLE;
@@ -549,6 +649,13 @@ int glutCreateWindow (const char *title)
i--;
continue;
}
+
+ if(mask & GLUT_MULTISAMPLE) {
+ attribs[i] = GLFBDEV_MULTISAMPLE;
+ attribs[++i] = NumSamples;
+ mask &= ~GLUT_MULTISAMPLE;
+ continue;
+ }
sprintf(exiterror, "Invalid mode from glutInitDisplayMode\n");
exit(0);
@@ -560,23 +667,37 @@ int glutCreateWindow (const char *title)
sprintf(exiterror, "Failure to create Visual\n");
exit(0);
}
+}
- size = VarInfo.xres_virtual * VarInfo.yres_virtual
- * VarInfo.bits_per_pixel / 8;
- if(DisplayMode & GLUT_DOUBLE) {
- if(!(BackBuffer = malloc(size))) {
- sprintf(exiterror, "Failed to allocate double buffer\n");
- exit(0);
- }
- } else
- BackBuffer = FrameBuffer;
-
- if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
- FrameBuffer, BackBuffer, size))) {
- sprintf(exiterror, "Failure to create Buffer\n");
- exit(0);
+int glutCreateWindow (const char *title)
+{
+ if(Initialized == 0) {
+ int argc = 0;
+ char *argv[] = {NULL};
+ glutInit(&argc, argv);
}
+ if(Context)
+ return 0;
+
+ if(DisplayMode & GLUT_INDEX)
+ VarInfo.bits_per_pixel = 8;
+ else
+ if(VarInfo.bits_per_pixel == 8)
+ VarInfo.bits_per_pixel = 32;
+
+ if (DesiredDepth)
+ VarInfo.bits_per_pixel = DesiredDepth;
+
+ VarInfo.xoffset = 0;
+ VarInfo.yoffset = 0;
+ VarInfo.nonstd = 0;
+ VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
+
+ SetVideoMode();
+ CreateVisual();
+ CreateBuffer();
+
if(!(Context = glFBDevCreateContext(Visual, NULL))) {
sprintf(exiterror, "Failure to create Context\n");
exit(0);
@@ -590,6 +711,8 @@ int glutCreateWindow (const char *title)
InitializeCursor();
InitializeMenus();
+ glutSetWindowTitle(title);
+
Visible = 1;
VisibleSwitch = 1;
Redisplay = 1;
@@ -628,12 +751,21 @@ void glutSwapBuffers(void)
{
glFlush();
- if(Visible && DisplayMode & GLUT_DOUBLE) {
- if(ActiveMenu)
- DrawMenus();
- if(MouseEnabled)
- DrawCursor();
+ if(ActiveMenu)
+ DrawMenus();
+ if(MouseEnabled)
+ DrawCursor();
+
+ if(DisplayMode & GLUT_DOUBLE && Visible) {
+ Swapping = 1;
glFBDevSwapBuffers(Buffer);
+ Swapping = 0;
+ }
+
+ if(VTSwitch) {
+ if(ioctl(ConsoleFD, VT_ACTIVATE, VTSwitch) < 0)
+ sprintf(exiterror, "Error switching console\n");
+ VTSwitch = 0;
}
}
@@ -643,6 +775,25 @@ void glutPositionWindow(int x, int y)
void glutReshapeWindow(int width, int height)
{
+ if(GameMode)
+ return;
+
+ if(!ParseFBModes(width, width, height, height, 0, MAX_VSYNC))
+ return;
+
+ SetVideoMode();
+ CreateBuffer();
+
+ if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
+ sprintf(exiterror, "Failure to Make Current\n");
+ exit(0);
+ }
+
+ InitializeMenus();
+
+ if(ReshapeFunc)
+ ReshapeFunc(VarInfo.xres, VarInfo.yres);
+ Redisplay = 1;
}
void glutFullScreen(void)
@@ -659,10 +810,12 @@ void glutPushWindow(void)
void glutShowWindow(void)
{
+ Visible = 1;
}
void glutHideWindow(void)
{
+ Visible = 0;
}
static void UnIconifyWindow(int sig)
@@ -677,6 +830,9 @@ static void UnIconifyWindow(int sig)
strerror(errno));
exit(0);
}
+ Redisplay = 1;
+ VisibleSwitch = 1;
+ Visible = 1;
}
void glutIconifyWindow(void)
@@ -691,6 +847,9 @@ void glutIconifyWindow(void)
void glutSetWindowTitle(const char *name)
{
+ /* escape code to set title in screen */
+ if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
+ printf("\033k%s\033\\", name);
}
void glutSetIconTitle(const char *name)