Linux frame buffer support from Ryan Nielsen <ran@gondolin.fortyoz.org> (thank

you). While not yet fully functional, it compiles and runs to the point of
failing to find a mode (probably my fault, that:), but there's no mouse
support yet and the keyboard input isn't playable.
This commit is contained in:
Bill Currie 2001-02-02 05:56:53 +00:00
parent 17e9aa044b
commit ff12a738b5
10 changed files with 2374 additions and 6 deletions

View file

@ -54,6 +54,11 @@ AC_PROG_CC
AC_PROG_CPP
AC_PROG_LN_S
AC_PROG_RANLIB
AM_PROG_LEX
AC_PROG_YACC
AC_CHECK_LIB(l, main, LEXLIB="-ll", AC_CHECK_LIB(fl, main, LEXLIB="-lfl"))
AC_SUBST(LEXLIB)
set $CC
if test "$1" = gcc; then
@ -376,6 +381,17 @@ AC_SUBST(HAVE_GGI)
AC_SUBST(GGI_CFLAGS)
AC_SUBST(GGI_LIBS)
dnl Checks for Linux FBDev support
AC_ARG_WITH(fbdev,
[ --with-fbdev use Linux framebuffer device],
HAVE_FBDEV=$withval, HAVE_FBDEV=auto)
if test "x$HAVE_FBDEV" != xno; then
dnl We should still be able to compile it even if
dnl there is no fbdev support in the running kernel
AC_CHECK_HEADER(linux/fb.h, HAVE_FBDEV=yes, HAVE_FBDEV=no)
fi
AC_SUBST(HAVE_FBDEV)
dnl Checks for SVGALib support
AC_ARG_WITH(svga,
[ --with-svga[=DIR] use SVGALib found in DIR],
@ -1230,12 +1246,13 @@ dnl ==================================================================
AC_ARG_WITH(clients,
[ --with-clients=<list> compile clients in <list>;
3dfx,ggi,glx,mgl,sdl,sgl,svga,x11],
3dfx,fbdev,ggi,glx,mgl,sdl,sgl,svga,x11],
clients="$withval",
clients="all"
)
if test "$clients" = "all"; then
ENABLE_3DFX=yes
ENABLE_FBDEV=yes
ENABLE_GGI=yes
ENABLE_GLX=yes
ENABLE_MGL=yes
@ -1245,6 +1262,7 @@ if test "$clients" = "all"; then
ENABLE_X11=yes
else
ENABLE_3DFX=no
ENABLE_FBDEV=no
ENABLE_GGI=no
ENABLE_GLX=no
ENABLE_MGL=no
@ -1258,6 +1276,9 @@ else
3dfx)
ENABLE_3DFX=yes
;;
fbdev)
ENABLE_FBDEV=yes
;;
ggi)
ENABLE_GGI=yes
;;
@ -1295,6 +1316,10 @@ if test "x$HAVE_TDFXGL" = xyes -a "x$ENABLE_3DFX" = xyes; then
TARGETS="$TARGETS qf-client-3dfx\$(EXEEXT)"
CL_TARGETS="$CL_TARGETS 3dfx"
fi
if test "x$HAVE_FBDEV" = xyes -a "x$ENABLE_FBDEV" = xyes; then
TARGETS="$TARGETS qf-client-fbdev\$(EXEEXT)"
CL_TARGETS="$CL_TARGETS FBDEV"
fi
if test "x$HAVE_GGI" = xyes -a "x$ENABLE_GGI" = xyes; then
TARGETS="$TARGETS qf-client-ggi\$(EXEEXT)"
CL_TARGETS="$CL_TARGETS GGI"

84
include/fbset.h Normal file
View file

@ -0,0 +1,84 @@
/*
* Linux Frame Buffer Device Configuration
*
* © Copyright 1995-1998 by Geert Uytterhoeven
* (Geert.Uytterhoeven@cs.kuleuven.ac.be)
*
* --------------------------------------------------------------------------
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details.
*/
#include <stdio.h>
#include <sys/types.h>
#ifdef __GLIBC__
#include <asm/types.h>
#endif
#include <linux/fb.h>
#define FBSET_VERSION "Linux Frame Buffer Device Configuration " \
"Version 2.1 (23/06/1999)\n" \
"(C) Copyright 1995-1999 by Geert Uytterhoeven\n"
#define LOW (0)
#define HIGH (1)
#define FALSE (0)
#define TRUE (1)
struct color {
unsigned int length;
unsigned int offset;
};
struct VideoMode {
struct VideoMode *next;
char *name;
/* geometry */
__u32 xres;
__u32 yres;
__u32 vxres;
__u32 vyres;
__u32 depth;
__u32 nonstd;
/* acceleration */
__u32 accel_flags;
/* timings */
__u32 pixclock;
__u32 left;
__u32 right;
__u32 upper;
__u32 lower;
__u32 hslen;
__u32 vslen;
/* flags */
unsigned hsync : 1;
unsigned vsync : 1;
unsigned csync : 1;
unsigned gsync : 1;
unsigned extsync : 1;
unsigned bcast : 1;
unsigned laced : 1;
unsigned dblscan : 1;
unsigned grayscale : 1;
/* scanrates */
double drate;
double hrate;
double vrate;
/* RGB entries */
struct color red, green, blue, transp;
};
extern FILE *yyin;
extern int line;
extern const char *Opt_modedb;
extern int yyparse(void);
extern void Die(const char *fmt, ...) __attribute__ ((noreturn));
extern void AddVideoMode(const struct VideoMode *vmode);
extern void makeRGBA(struct VideoMode *vmode, const char* opt);

View file

@ -87,7 +87,8 @@ void VID_Update (vrect_t *rects);
// sets the mode; only used by the Quake engine for resetting to mode 0 (the
// base mode) on memory allocation failures
int VID_SetMode (int modenum, unsigned char *palette);
// or not
// int VID_SetMode (int modenum, unsigned char *palette);
// called only on Win32, when pause happens, so the mouse can be released
void VID_HandlePause (qboolean pause);

4
source/.gitignore vendored
View file

@ -41,3 +41,7 @@ qwaq-client-x11
qwaq-client-x11.exe
qwaq-server
qwaq-server.exe
fbset_modes_y.c
fbset_modes_y.h
fbset_modes_l.c
qf-client-fbdev

View file

@ -36,9 +36,9 @@ INCLUDES= -I$(top_srcdir)/include $(GGI_CFLAGS) $(MGL_CFLAGS) $(SDL_CFLAGS) $(SV
bin_PROGRAMS = @TARGETS@
EXTRA_PROGRAMS= qf-server \
qf-client-3dfx qf-client-ggi qf-client-glx qf-client-mgl \
qf-client-sdl qf-client-sgl qf-client-svga qf-client-wgl \
qf-client-x11
qf-client-3dfx qf-client-fbdev qf-client-ggi qf-client-glx \
qf-client-mgl qf-client-sdl qf-client-sgl qf-client-svga \
qf-client-wgl qf-client-x11
noinst_LIBRARIES= libqfcd.a libqfjs.a libqfnet.a libqfsnd.a libqfsys_cl.a libqfsys_sv.a
@ -200,6 +200,22 @@ soft_SOURCES= d_edge.c d_fill.c d_init.c d_modech.c \
screen.c $(soft_ASM) sw_model_alias.c sw_model_brush.c \
sw_model_sprite.c
#
# ... Linux FBDev
#
YFLAGS = -d
fbdev_SOURCES= fbset.c fbset_modes_y.y fbset_modes_l.l vid_fbdev.c in_fbdev.c
YACCLEX_CLEANFILES= fbset_modes_y.c fbset_modes_y.h fbset_modes_y.tab.h fbset_modes_l.c
fbset_modes_y.o: fbset_modes_y.c
$(CC) $(INCLUDES) $(CFLAGS) -Wno-error -c fbset_modes_y.c
fbset_modes_l.o: fbset_modes_l.c
$(CC) $(INCLUDES) $(CFLAGS) -Wno-error -c fbset_modes_l.c
qf_client_fbdev_SOURCES= $(common_SOURCES) $(client_SOURCES) $(soft_SOURCES) $(fbdev_SOURCES)
qf_client_fbdev_LDADD= $(CLIENT_LIBS)
qf_client_fbdev_DEPENDENCIES=libqfnet.a libqfsys_cl.a libqfsnd.a libqfcd.a libqfjs.a
#
# ... GGI
#
@ -304,4 +320,4 @@ EXTRA_DIST= makefile.win \
qf-client-sgl.mak qf-client-wgl.mak qf-client-win.mak
# Kill the temp files, hopefully.
CLEANFILES = *.i *.s
CLEANFILES = *.i *.s $(YACCLEX_CLEANFILES)

1065
source/fbset.c Normal file

File diff suppressed because it is too large Load diff

138
source/fbset_modes_l.l Normal file
View file

@ -0,0 +1,138 @@
/*
* Linux Frame Buffer Device Configuration
*
* © Copyright 1995-1998 by Geert Uytterhoeven
* (Geert.Uytterhoeven@cs.kuleuven.ac.be)
*
* --------------------------------------------------------------------------
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details.
*/
%{
#define YYSTYPE long
#include <string.h>
#include <stdlib.h>
#define Die Sys_Error
#include "fbset.h"
#include "fbset_modes_y.h"
struct keyword {
const char *name;
int token;
int value;
};
static struct keyword keywords[] = {
{ "mode", MODE, 0 },
{ "geometry", GEOMETRY, 0 },
{ "timings", TIMINGS, 0 },
{ "hsync", HSYNC, 0 },
{ "vsync", VSYNC, 0 },
{ "csync", CSYNC, 0 },
{ "gsync", GSYNC, 0 },
{ "extsync", EXTSYNC, 0 },
{ "bcast", BCAST, 0 },
{ "laced", LACED, 0 },
{ "double", DOUBLE, 0 },
{ "rgba", RGBA, 0 },
{ "nonstd", NONSTD, 0 },
{ "accel", ACCEL, 0 },
{ "grayscale", GRAYSCALE, 0 },
{ "endmode", ENDMODE, 0 },
{ "low", POLARITY, LOW },
{ "high", POLARITY, HIGH },
{ "false", BOOLEAN, FALSE },
{ "true", BOOLEAN, TRUE },
{ "", -1, 0 }
};
int line = 1;
void yyerror(const char *s)
{
Die("%s:%d: %s\n", Opt_modedb, line, s);
}
int yywrap(void)
{
return 1;
}
static int FindToken(const char *s)
{
int i;
for (i = 0; keywords[i].token > 0; i++)
if (!strcasecmp(s, keywords[i].name)) {
yylval = keywords[i].value;
return keywords[i].token;
}
Die("%s:%d: Unknown keyword `%s'\n", Opt_modedb, line, s);
}
static const char *CopyString(const char *s)
{
int len;
char *s2;
len = strlen(s)-2;
if (!(s2 = malloc(len+1)))
Die("No memory\n");
strncpy(s2, s+1, len);
s2[len] = '\0';
return s2;
}
%}
keyword [a-zA-Z][a-zA-Z0-9]*
number [0-9]*
string \"[^\"\n]*\"
comment \#([^\n]*)
space [ \t]+
junk .
%%
{keyword} {
return FindToken(yytext);
}
{number} {
yylval = strtoul(yytext, NULL, 0);
return NUMBER;
}
{string} {
yylval = (unsigned long)CopyString(yytext);
return STRING;
}
{comment}$ break;
{space} break;
\n {
line++;
break;
}
{junk} {
Die("%s:%d: Invalid token `%s'\n", Opt_modedb, line, yytext);
}
%%

176
source/fbset_modes_y.y Normal file
View file

@ -0,0 +1,176 @@
/*
* Linux Frame Buffer Device Configuration
*
* © Copyright 1995-1998 by Geert Uytterhoeven
* (Geert.Uytterhoeven@cs.kuleuven.ac.be)
*
* --------------------------------------------------------------------------
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details.
*/
%{
#define YYSTYPE long
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Die Sys_Error
#include "fbset.h"
extern int yylex(void);
extern void yyerror(const char *s);
extern int line;
static struct VideoMode VideoMode;
static void ClearVideoMode(void)
{
memset(&VideoMode, 0, sizeof(VideoMode));
VideoMode.accel_flags = FB_ACCELF_TEXT;
}
%}
%start file
%token MODE GEOMETRY TIMINGS HSYNC VSYNC CSYNC GSYNC EXTSYNC BCAST LACED DOUBLE
RGBA NONSTD ACCEL GRAYSCALE
ENDMODE POLARITY BOOLEAN STRING NUMBER
%%
file : vmodes
;
vmodes : /* empty */
| vmodes vmode
;
vmode : MODE STRING geometry timings options ENDMODE
{
VideoMode.name = (char *)$2;
AddVideoMode(&VideoMode);
ClearVideoMode();
}
;
geometry : GEOMETRY NUMBER NUMBER NUMBER NUMBER NUMBER
{
ClearVideoMode();
VideoMode.xres = $2;
VideoMode.yres = $3;
VideoMode.vxres = $4;
VideoMode.vyres = $5;
VideoMode.depth = $6;
}
;
timings : TIMINGS NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER
{
VideoMode.pixclock = $2;
VideoMode.left = $3;
VideoMode.right = $4;
VideoMode.upper = $5;
VideoMode.lower = $6;
VideoMode.hslen = $7;
VideoMode.vslen = $8;
}
;
options : /* empty */
| options hsync
| options vsync
| options csync
| options gsync
| options extsync
| options bcast
| options laced
| options double
| options rgba
| options nonstd
| options accel
| options grayscale
;
hsync : HSYNC POLARITY
{
VideoMode.hsync = $2;
}
;
vsync : VSYNC POLARITY
{
VideoMode.vsync = $2;
}
;
csync : CSYNC POLARITY
{
VideoMode.csync = $2;
}
;
gsync : GSYNC POLARITY
{
VideoMode.gsync = $2;
}
;
extsync : EXTSYNC BOOLEAN
{
VideoMode.extsync = $2;
}
;
bcast : BCAST BOOLEAN
{
VideoMode.bcast = $2;
}
;
laced : LACED BOOLEAN
{
VideoMode.laced = $2;
}
;
double : DOUBLE BOOLEAN
{
VideoMode.dblscan = $2;
}
;
rgba : RGBA STRING
{
makeRGBA(&VideoMode, (const char*)$2);
}
;
nonstd : NONSTD NUMBER
{
VideoMode.nonstd = $2;
}
;
accel : ACCEL BOOLEAN
{
VideoMode.accel_flags = $2;
}
;
grayscale : GRAYSCALE BOOLEAN
{
VideoMode.grayscale = $2;
}
;
%%

154
source/in_fbdev.c Normal file
View file

@ -0,0 +1,154 @@
/*
in_fbdev.c
fix this!
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "protocol.h"
#include "cvar.h"
#include "keys.h"
#include <termios.h>
#include <unistd.h>
cvar_t *_windowed_mouse;
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int
fd_blocking (int fd, int on)
{
int x;
#if defined(_POSIX_SOURCE) || !defined(FIONBIO)
#if !defined(O_NONBLOCK)
# if defined(O_NDELAY)
# define O_NONBLOCK O_NDELAY
# endif
#endif
if ((x = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
if (on)
x &= ~O_NONBLOCK;
else
x |= O_NONBLOCK;
return fcntl(fd, F_SETFL, x);
#else
x = !on;
return ioctl(fd, FIONBIO, &x);
#endif
}
static struct termios old_tty, new_tty;
static int tty_fd = 0;
void
IN_Init (void)
{
fd_blocking(0, 0);
tcgetattr(tty_fd, &old_tty);
new_tty = old_tty;
new_tty.c_cc[VMIN] = 1;
new_tty.c_cc[VTIME] = 0;
new_tty.c_lflag &= ~ICANON;
new_tty.c_iflag &= ~IXON;
tcsetattr(tty_fd, TCSADRAIN, &new_tty);
}
void
IN_Init_Cvars (void)
{
}
void
IN_Shutdown (void)
{
}
void
IN_SendKeyEvents (void)
{
int k, down;
char buf[4];
if (read(0, buf, 1) == 1) {
k = buf[0];
switch (k) {
case '\r':
case '\n':
k = K_ENTER;
break;
case '\033':
if (read(0, buf, 2) != 2)
break;
switch (buf[1]) {
case 'A':
k = K_UPARROW;
break;
case 'B':
k = K_DOWNARROW;
break;
case 'C':
k = K_RIGHTARROW;
break;
case 'D':
k = K_LEFTARROW;
break;
}
break;
}
down = 1;
Key_Event(k, -1, down);
Key_Event(k, -1, !down);
}
}
void
IN_Commands (void)
{
}
void
IN_Move (usercmd_t *cmd)
{
}
/*
===========
IN_ModeChanged
===========
*/
void
IN_ModeChanged (void)
{
}

705
source/vid_fbdev.c Normal file
View file

@ -0,0 +1,705 @@
/*
vid_fbdev.c
Linux FBDev video routines
based on vid_svgalib.c
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 1999-2000 Nelson Rush.
Copyright (C) 1999-2000 Marcus Sundberg [mackan@stacken.kth.se]
Copyright (C) 1999-2000 David Symonds [xoxus@usa.net]
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(HAVE_SYS_IO_H)
# include <sys/io.h>
#elif defined(HAVE_ASM_IO_H)
# include <asm/io.h>
#endif
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/page.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include "cmd.h"
#include "console.h"
#include "cvar.h"
#include "d_local.h"
#include "host.h"
#include "input.h"
#include "qargs.h"
#include "qendian.h"
#include "sys.h"
#include "fbset.h"
unsigned short d_8to16table[256];
extern void ReadModeDB(void);
extern struct VideoMode *FindVideoMode(const char *name);
void ConvertFromVideoMode(const struct VideoMode *vmode,
struct fb_var_screeninfo *var);
void ConvertToVideoMode(const struct fb_var_screeninfo *var,
struct VideoMode *vmode);
extern struct VideoMode *VideoModes;
static struct VideoMode current_mode;
static char current_name[32];
static int num_modes;
static int fb_fd = -1;
static int tty_fd = 0;
static byte vid_current_palette[768];
static int fbdev_inited = 0;
static int fbdev_backgrounded = 0;
static int UseDisplay = 1;
static cvar_t *vid_mode;
static cvar_t *vid_redrawfull;
static cvar_t *vid_waitforrefresh;
static char *framebuffer_ptr;
static byte backingbuf[48 * 24];
void
D_BeginDirectRect (int x, int y, byte * pbitmap, int width, int height)
{
int i, j, reps, repshift, offset, off;
if (!fbdev_inited || !vid.direct || fbdev_backgrounded)
return;
if (vid.aspect > 1.5) {
reps = 2;
repshift = 1;
} else {
reps = 1;
repshift = 0;
}
for (i = 0; i < (height << repshift); i += reps) {
for (j = 0; j < reps; j++) {
offset = x + ((y << repshift) + i + j)
* vid.rowbytes;
off = offset % 0x10000;
memcpy (&backingbuf[(i + j) * 24], vid.direct + off, width);
memcpy (vid.direct + off,
&pbitmap[(i >> repshift) * width], width);
}
}
}
void
D_EndDirectRect (int x, int y, int width, int height)
{
int i, j, reps, repshift, offset, off;
if (!fbdev_inited || !vid.direct || fbdev_backgrounded)
return;
if (vid.aspect > 1.5) {
reps = 2;
repshift = 1;
} else {
reps = 1;
repshift = 0;
}
for (i = 0; i < (height << repshift); i += reps) {
for (j = 0; j < reps; j++) {
offset = x + ((y << repshift) + i + j)
* vid.rowbytes;
off = offset % 0x10000;
memcpy (vid.direct + off, &backingbuf[(i + j) * 24], width);
}
}
}
static void
VID_Gamma_f (void)
{
float gamma, f, inf;
unsigned char palette[768];
int i;
if (Cmd_Argc () == 2) {
gamma = atof (Cmd_Argv (1));
for (i = 0; i < 768; i++) {
f = pow ((host_basepal[i] + 1) / 256.0, gamma);
inf = f * 255 + 0.5;
if (inf < 0)
inf = 0;
if (inf > 255)
inf = 255;
palette[i] = inf;
}
VID_SetPalette (palette);
/* Force a surface cache flush */
vid.recalc_refdef = 1;
}
}
static void
VID_DescribeMode_f (void)
{
char *modestr;
struct VideoMode *vmode;
modestr = Cmd_Argv(1);
vmode = FindVideoMode(modestr);
if (!vmode) {
Con_Printf ("Invalid video mode: %s!\n", modestr);
return;
}
Con_Printf ("%s: %d x %d - %d bpp - %5.3f Hz\n", vmode->name,
vmode->xres, vmode->yres, vmode->depth, vmode->vrate);
}
static void
VID_DescribeModes_f (void)
{
struct VideoMode *vmode;
for (vmode = VideoModes; vmode; vmode = vmode->next) {
Con_Printf ("%s: %d x %d - %d bpp - %5.3f Hz\n", vmode->name,
vmode->xres, vmode->yres, vmode->depth, vmode->vrate);
}
}
/*
================
VID_NumModes
================
*/
static int
VID_NumModes (void)
{
struct VideoMode *vmode;
int i = 0;
for (vmode = VideoModes; vmode; vmode = vmode->next)
i++;
return i;
}
static void
VID_NumModes_f (void)
{
Con_Printf ("%d modes\n", VID_NumModes ());
}
int VID_SetMode (char *name, unsigned char *palette);
extern void fbset_main (int argc, char **argv);
static void
VID_fbset_f (void)
{
int i, argc;
char *argv[32];
argc = Cmd_Argc();
if (argc > 32)
argc = 32;
argv[0] = "vid_fbset";
for (i = 1; i < argc; i++) {
argv[i] = Cmd_Argv(i);
}
fbset_main(argc, argv);
}
static void
VID_Debug_f (void)
{
Con_Printf ("mode: %s\n", current_mode.name);
Con_Printf ("height x width: %d x %d\n", current_mode.xres, current_mode.yres);
Con_Printf ("bpp: %d\n", current_mode.depth);
Con_Printf ("vrate: %5.3f\n", current_mode.vrate);
Con_Printf ("vid.aspect: %f\n", vid.aspect);
}
static void
VID_InitModes (void)
{
ReadModeDB();
num_modes = VID_NumModes();
}
static char *
get_mode (char *name, int width, int height, int depth)
{
struct VideoMode *vmode;
for (vmode = VideoModes; vmode; vmode = vmode->next) {
if (name) {
if (!strcmp(vmode->name, name))
return name;
} else {
if (vmode->xres == width
&& vmode->yres == height
&& vmode->depth == depth)
return vmode->name;
}
}
Sys_Printf ("Mode %dx%d (%d bits) not supported\n",
width, height, depth);
return "640x480-60";
}
void
VID_InitBuffers (void)
{
int buffersize, zbuffersize, cachesize;
void *vid_surfcache;
// Calculate the sizes we want first
buffersize = vid.rowbytes * vid.height;
zbuffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
cachesize = D_SurfaceCacheForRes (vid.width, vid.height);
// Free the old screen buffer
if (vid.buffer) {
free (vid.buffer);
vid.conbuffer = vid.buffer = NULL;
}
// Free the old z-buffer
if (d_pzbuffer) {
free (d_pzbuffer);
d_pzbuffer = NULL;
}
// Free the old surface cache
vid_surfcache = D_SurfaceCacheAddress ();
if (vid_surfcache) {
D_FlushCaches ();
free (vid_surfcache);
vid_surfcache = NULL;
}
// Allocate the new screen buffer
vid.conbuffer = vid.buffer = calloc (buffersize, 1);
if (!vid.conbuffer) {
Sys_Error ("Not enough memory for video mode\n");
}
// Allocate the new z-buffer
d_pzbuffer = calloc (zbuffersize, 1);
if (!d_pzbuffer) {
free (vid.buffer);
vid.conbuffer = vid.buffer = NULL;
Sys_Error ("Not enough memory for video mode\n");
}
// Allocate the new surface cache; free the z-buffer if we fail
vid_surfcache = calloc (cachesize, 1);
if (!vid_surfcache) {
free (vid.buffer);
free (d_pzbuffer);
vid.conbuffer = vid.buffer = NULL;
d_pzbuffer = NULL;
Sys_Error ("Not enough memory for video mode\n");
}
D_InitCaches (vid_surfcache, cachesize);
}
static unsigned char *fb_map_addr = 0;
static unsigned long fb_map_length = 0;
static struct fb_var_screeninfo orig_var;
void
VID_Shutdown (void)
{
Sys_Printf ("VID_Shutdown\n");
if (!fbdev_inited)
return;
if (munmap(fb_map_addr, fb_map_length) == -1) {
Sys_Printf("could not unmap framebuffer at %p: %s\n",
fb_map_addr, strerror(errno));
} else {
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &orig_var))
Sys_Printf ("failed to get var screen info\n");
}
close(fb_fd);
if (UseDisplay) {
ioctl(tty_fd, KDSETMODE, KD_TEXT);
write(tty_fd, "\033]R", 3); /* reset palette */
}
fbdev_inited = 0;
}
void
VID_ShiftPalette (unsigned char *p)
{
VID_SetPalette (p);
}
static void
loadpalette (unsigned short *red, unsigned short *green, unsigned short *blue)
{
struct fb_cmap cmap;
cmap.len = 256;
cmap.red = red;
cmap.green = green;
cmap.blue = blue;
cmap.transp = NULL;
cmap.start = 0;
if (-1 == ioctl(fb_fd, FBIOPUTCMAP, (void *)&cmap))
Sys_Error("ioctl FBIOPUTCMAP %s\n", strerror(errno));
}
void
VID_SetPalette (byte * palette)
{
static unsigned short tmppalr[256], tmppalg[256], tmppalb[256];
unsigned short i, *tpr, *tpg, *tpb;
if (!fbdev_inited || fbdev_backgrounded || fb_fd < 0)
return;
memcpy (vid_current_palette, palette, sizeof (vid_current_palette));
if (current_mode.depth == 8) {
tpr = tmppalr;
tpg = tmppalg;
tpb = tmppalb;
for (i = 0; i < 256; i++) {
*tpr++ = (*palette++) << 8;
*tpg++ = (*palette++) << 8;
*tpb++ = (*palette++) << 8;
}
if (UseDisplay) {
loadpalette(tmppalr, tmppalg, tmppalb);
}
}
}
int
VID_SetMode (char *name, unsigned char *palette)
{
struct VideoMode *vmode;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
int err;
unsigned long smem_start, smem_offset;
vmode = FindVideoMode(name);
if (!vmode) {
Cvar_Set (vid_mode, current_mode.name);
// Con_Printf ("No such video mode: %s\n", name);
return 0;
}
current_mode = *vmode;
Cvar_Set (vid_mode, current_mode.name);
strncpy(current_name, current_mode.name, sizeof(current_name)-1);
current_name[31] = 0;
vid.width = vmode->xres;
vid.height = vmode->yres;
vid.rowbytes = vmode->xres * (vmode->depth >> 3);
vid.aspect = ((float) vid.height / (float) vid.width) * (320.0 / 240.0);
vid.colormap = (pixel_t *) host_colormap;
vid.fullbright = 256 - LittleLong (*((int *) vid.colormap + 2048));
vid.conrowbytes = vid.rowbytes;
vid.conwidth = vid.width;
vid.conheight = vid.height;
vid.numpages = 1;
vid.maxwarpwidth = WARP_WIDTH;
vid.maxwarpheight = WARP_HEIGHT;
if (fb_map_addr) {
if (munmap(fb_map_addr, fb_map_length) == -1) {
Sys_Printf("could not unmap framebuffer at %p: %s\n",
fb_map_addr, strerror(errno));
}
}
ConvertFromVideoMode(&current_mode, &var);
err = ioctl(fb_fd, FBIOPUT_VSCREENINFO, &var);
if (err)
Sys_Error ("Video mode failed: %s\n", name);
ConvertToVideoMode(&var, &current_mode);
current_mode.name = current_name;
VID_SetPalette (palette);
err = ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix);
if (err)
Sys_Error ("Video mode failed: %s\n", name);
smem_start = (unsigned long)fix.smem_start & PAGE_MASK;
smem_offset = (unsigned long)fix.smem_start & ~PAGE_MASK;
fb_map_length = (smem_offset+fix.smem_len+~PAGE_MASK) & PAGE_MASK;
fb_map_addr = (char *)mmap(0, fb_map_length, PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (!fb_map_addr)
Sys_Error ("This mode isn't hapnin'\n");
vid.direct = framebuffer_ptr = fb_map_addr;
// alloc screen buffer, z-buffer, and surface cache
VID_InitBuffers ();
if (!fbdev_inited) {
fbdev_inited = 1;
}
/* Force a surface cache flush */
vid.recalc_refdef = 1;
return 1;
}
static void
fb_switch_handler (int sig)
{
if (sig == SIGUSR1) {
fbdev_backgrounded = 1;
} else if (sig == SIGUSR2) {
fbdev_backgrounded = 2;
}
}
static void
fb_switch_release (void)
{
ioctl(tty_fd, VT_RELDISP, 1);
}
static void
fb_switch_acquire (void)
{
ioctl(tty_fd, VT_RELDISP, VT_ACKACQ);
}
static void
fb_switch_init (void)
{
struct sigaction act;
struct vt_mode vtmode;
memset(&act, 0, sizeof(act));
act.sa_handler = fb_switch_handler;
sigemptyset(&act.sa_mask);
sigaction(SIGUSR1, &act, 0);
sigaction(SIGUSR2, &act, 0);
if (ioctl(tty_fd, VT_GETMODE, &vtmode)) {
Sys_Error("ioctl VT_GETMODE: %s\n", strerror(errno));
}
vtmode.mode = VT_PROCESS;
vtmode.waitv = 0;
vtmode.relsig = SIGUSR1;
vtmode.acqsig = SIGUSR2;
if (ioctl(tty_fd, VT_SETMODE, &vtmode)) {
Sys_Error("ioctl VT_SETMODE: %s\n", strerror(errno));
}
}
void
VID_Init (unsigned char *palette)
{
int w, h, d;
struct VideoMode *vmode;
char *modestr;
char *fbname;
// plugin_load("in_fbdev.so");
if (fbdev_inited)
return;
Cmd_AddCommand ("gamma", VID_Gamma_f, "No Description");
if (UseDisplay) {
fbname = getenv("FRAMEBUFFER");
if (!fbname)
fbname = "/dev/fb0";
fb_fd = open(fbname, O_RDWR);
if (fb_fd < 0)
Sys_Error ("failed to open fb device\n");
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &orig_var))
Sys_Error ("failed to get var screen info\n");
fb_switch_init();
VID_InitModes ();
Cmd_AddCommand ("vid_nummodes", VID_NumModes_f, "No Description");
Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f, "No Description");
Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f, "No Description");
Cmd_AddCommand ("vid_debug", VID_Debug_f, "No Description");
Cmd_AddCommand ("vid_fbset", VID_fbset_f, "No Description");
/* Interpret command-line params */
w = h = d = 0;
if (getenv ("GFBDEVMODE")) {
modestr = get_mode (getenv ("GFBDEVMODE"), w, h, d);
} else if (COM_CheckParm ("-mode")) {
modestr = get_mode (com_argv[COM_CheckParm ("-mode") + 1], w, h, d);
} else if (COM_CheckParm ("-w") || COM_CheckParm ("-h")
|| COM_CheckParm ("-d")) {
if (COM_CheckParm ("-w")) {
w = atoi (com_argv[COM_CheckParm ("-w") + 1]);
}
if (COM_CheckParm ("-h")) {
h = atoi (com_argv[COM_CheckParm ("-h") + 1]);
}
if (COM_CheckParm ("-d")) {
d = atoi (com_argv[COM_CheckParm ("-d") + 1]);
}
modestr = get_mode (0, w, h, d);
} else {
modestr = "640x480-60";
}
/* Set vid parameters */
vmode = FindVideoMode(modestr);
if (!vmode)
Sys_Error("no video mode %s\n", modestr);
current_mode = *vmode;
ioctl(tty_fd, KDSETMODE, KD_GRAPHICS);
VID_SetMode (current_mode.name, palette);
Con_CheckResize (); // Now that we have a window size, fix console
VID_SetPalette (palette);
}
}
void
VID_Init_Cvars ()
{
vid_mode = Cvar_Get ("vid_mode", "0", CVAR_NONE, "Sets the video mode");
vid_redrawfull = Cvar_Get ("vid_redrawfull", "0", CVAR_NONE,
"Redraw entire screen each frame instead of just dirty areas");
vid_waitforrefresh = Cvar_Get ("vid_waitforrefresh", "0", CVAR_ARCHIVE,
"Wait for vertical retrace before drawing next frame");
}
void
VID_Update (vrect_t *rects)
{
if (!fbdev_inited)
return;
if (fbdev_backgrounded) {
if (fbdev_backgrounded == 3) {
return;
} else if (fbdev_backgrounded == 2) {
fb_switch_acquire();
fbdev_backgrounded = 0;
VID_SetPalette(vid_current_palette);
} else if (fbdev_backgrounded == 1) {
fb_switch_release();
fbdev_backgrounded = 3;
return;
}
}
if (vid_waitforrefresh->int_val) {
// ???
}
if (vid_redrawfull->int_val) {
double *d = (double *)framebuffer_ptr, *s = (double *)vid.buffer;
double *ends = (double *)(vid.buffer + vid.height*vid.rowbytes);
while (s < ends)
*d++ = *s++;
} else {
while (rects) {
int height, width, lineskip, i, j, xoff, yoff;
double *d, *s;
height = rects->height;
width = rects->width / sizeof(double);
xoff = rects->x;
yoff = rects->y;
lineskip = (vid.width - (xoff + rects->width)) / sizeof(double);
d = (double *)(framebuffer_ptr + yoff * vid.rowbytes + xoff);
s = (double *)(vid.buffer + yoff * vid.rowbytes + xoff);
for (i = yoff; i < height; i++) {
for (j = xoff; j < width; j++)
*d++ = *s++;
d += lineskip;
s += lineskip;
}
rects = rects->pnext;
}
}
if (current_mode.name && strcmp(vid_mode->string, current_mode.name)) {
VID_SetMode (vid_mode->string, vid_current_palette);
}
}
void
VID_LockBuffer (void)
{
}
void
VID_UnlockBuffer (void)
{
}
void
VID_SetCaption (char *text)
{
}