📄 sdl_fbvideo.c
字号:
case FB_ACCEL_MATROX_MGA1064SG:
case FB_ACCEL_MATROX_MGA2164W:
case FB_ACCEL_MATROX_MGA2164W_AGP:
case FB_ACCEL_MATROX_MGAG100:
/*case FB_ACCEL_MATROX_MGAG200: G200 acceleration broken! */
case FB_ACCEL_MATROX_MGAG400:
#ifdef FBACCEL_DEBUG
printf("Matrox hardware accelerator!\n");
#endif
FB_MatroxAccel(this, finfo.accel);
break;
case FB_ACCEL_3DFX_BANSHEE:
#ifdef FBACCEL_DEBUG
printf("3DFX hardware accelerator!\n");
#endif
FB_3DfxAccel(this, finfo.accel);
break;
case FB_ACCEL_NV3:
case FB_ACCEL_NV4:
#ifdef FBACCEL_DEBUG
printf("NVidia hardware accelerator!\n");
#endif
FB_RivaAccel(this, finfo.accel);
break;
default:
#ifdef FBACCEL_DEBUG
printf("Unknown hardware accelerator.\n");
#endif
break;
}
}
/* Enable mouse and keyboard support */
if ( FB_OpenKeyboard(this) < 0 ) {
FB_VideoQuit(this);
return(-1);
}
if ( FB_OpenMouse(this) < 0 ) {
const char *sdl_nomouse;
sdl_nomouse = getenv("SDL_NOMOUSE");
if ( ! sdl_nomouse ) {
SDL_SetError("Unable to open mouse");
FB_VideoQuit(this);
return(-1);
}
}
/* We're done! */
return(0);
}
static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
}
/* Various screen update functions available */
static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
#ifdef VGA16_FBCON_SUPPORT
static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects);
#endif
#ifdef FBCON_DEBUG
static void print_vinfo(struct fb_var_screeninfo *vinfo)
{
fprintf(stderr, "Printing vinfo:\n");
fprintf(stderr, "\txres: %d\n", vinfo->xres);
fprintf(stderr, "\tyres: %d\n", vinfo->yres);
fprintf(stderr, "\txres_virtual: %d\n", vinfo->xres_virtual);
fprintf(stderr, "\tyres_virtual: %d\n", vinfo->yres_virtual);
fprintf(stderr, "\txoffset: %d\n", vinfo->xoffset);
fprintf(stderr, "\tyoffset: %d\n", vinfo->yoffset);
fprintf(stderr, "\tbits_per_pixel: %d\n", vinfo->bits_per_pixel);
fprintf(stderr, "\tgrayscale: %d\n", vinfo->grayscale);
fprintf(stderr, "\tnonstd: %d\n", vinfo->nonstd);
fprintf(stderr, "\tactivate: %d\n", vinfo->activate);
fprintf(stderr, "\theight: %d\n", vinfo->height);
fprintf(stderr, "\twidth: %d\n", vinfo->width);
fprintf(stderr, "\taccel_flags: %d\n", vinfo->accel_flags);
fprintf(stderr, "\tpixclock: %d\n", vinfo->pixclock);
fprintf(stderr, "\tleft_margin: %d\n", vinfo->left_margin);
fprintf(stderr, "\tright_margin: %d\n", vinfo->right_margin);
fprintf(stderr, "\tupper_margin: %d\n", vinfo->upper_margin);
fprintf(stderr, "\tlower_margin: %d\n", vinfo->lower_margin);
fprintf(stderr, "\thsync_len: %d\n", vinfo->hsync_len);
fprintf(stderr, "\tvsync_len: %d\n", vinfo->vsync_len);
fprintf(stderr, "\tsync: %d\n", vinfo->sync);
fprintf(stderr, "\tvmode: %d\n", vinfo->vmode);
fprintf(stderr, "\tred: %d/%d\n", vinfo->red.length, vinfo->red.offset);
fprintf(stderr, "\tgreen: %d/%d\n", vinfo->green.length, vinfo->green.offset);
fprintf(stderr, "\tblue: %d/%d\n", vinfo->blue.length, vinfo->blue.offset);
fprintf(stderr, "\talpha: %d/%d\n", vinfo->transp.length, vinfo->transp.offset);
}
static void print_finfo(struct fb_fix_screeninfo *finfo)
{
fprintf(stderr, "Printing finfo:\n");
fprintf(stderr, "\tsmem_start = %p\n", (char *)finfo->smem_start);
fprintf(stderr, "\tsmem_len = %d\n", finfo->smem_len);
fprintf(stderr, "\ttype = %d\n", finfo->type);
fprintf(stderr, "\ttype_aux = %d\n", finfo->type_aux);
fprintf(stderr, "\tvisual = %d\n", finfo->visual);
fprintf(stderr, "\txpanstep = %d\n", finfo->xpanstep);
fprintf(stderr, "\typanstep = %d\n", finfo->ypanstep);
fprintf(stderr, "\tywrapstep = %d\n", finfo->ywrapstep);
fprintf(stderr, "\tline_length = %d\n", finfo->line_length);
fprintf(stderr, "\tmmio_start = %p\n", (char *)finfo->mmio_start);
fprintf(stderr, "\tmmio_len = %d\n", finfo->mmio_len);
fprintf(stderr, "\taccel = %d\n", finfo->accel);
}
#endif
static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo)
{
int matched;
FILE *fbmodes;
matched = 0;
fbmodes = fopen("/etc/fb.modes", "r");
if ( fbmodes ) {
/* FIXME: Parse the mode definition file */
fclose(fbmodes);
}
return(matched);
}
static int choose_vesa_mode(struct fb_var_screeninfo *vinfo)
{
int matched;
int i;
/* Check for VESA timings */
matched = 0;
for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
if ( (vinfo->xres == vesa_timings[i].xres) &&
(vinfo->yres == vesa_timings[i].yres) ) {
#ifdef FBCON_DEBUG
fprintf(stderr, "Using VESA timings for %dx%d\n",
vinfo->xres, vinfo->yres);
#endif
if ( vesa_timings[i].pixclock ) {
vinfo->pixclock = vesa_timings[i].pixclock;
}
vinfo->left_margin = vesa_timings[i].left;
vinfo->right_margin = vesa_timings[i].right;
vinfo->upper_margin = vesa_timings[i].upper;
vinfo->lower_margin = vesa_timings[i].lower;
vinfo->hsync_len = vesa_timings[i].hslen;
vinfo->vsync_len = vesa_timings[i].vslen;
vinfo->sync = vesa_timings[i].sync;
vinfo->vmode = vesa_timings[i].vmode;
matched = 1;
break;
}
}
return(matched);
}
#ifdef VGA16_FBCON_SUPPORT
static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
/* Set the terminal into graphics mode */
if ( FB_EnterGraphicsMode(this) < 0 ) {
return(NULL);
}
/* Restore the original palette */
FB_RestorePalette(this);
/* Set the video mode and get the final screen format */
if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
SDL_SetError("Couldn't get console screen info");
return(NULL);
}
cache_vinfo = vinfo;
#ifdef FBCON_DEBUG
fprintf(stderr, "Printing actual vinfo:\n");
print_vinfo(&vinfo);
#endif
if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
return(NULL);
}
current->format->palette->ncolors = 16;
/* Get the fixed information about the console hardware.
This is necessary since finfo.line_length changes.
*/
if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
SDL_SetError("Couldn't get console hardware info");
return(NULL);
}
#ifdef FBCON_DEBUG
fprintf(stderr, "Printing actual finfo:\n");
print_finfo(&finfo);
#endif
/* Save hardware palette, if needed */
FB_SavePalette(this, &finfo, &vinfo);
/* Set up the new mode framebuffer */
current->flags = SDL_FULLSCREEN;
current->w = vinfo.xres;
current->h = vinfo.yres;
current->pitch = current->w;
current->pixels = malloc(current->h*current->pitch);
/* Set the update rectangle function */
this->UpdateRects = FB_VGA16Update;
/* We're done */
return(current);
}
#endif /* VGA16_FBCON_SUPPORT */
static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
int i;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
char *surfaces_mem;
int surfaces_len;
/* Set the terminal into graphics mode */
if ( FB_EnterGraphicsMode(this) < 0 ) {
return(NULL);
}
/* Restore the original palette */
FB_RestorePalette(this);
/* Set the video mode and get the final screen format */
if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
SDL_SetError("Couldn't get console screen info");
return(NULL);
}
#ifdef FBCON_DEBUG
fprintf(stderr, "Printing original vinfo:\n");
print_vinfo(&vinfo);
#endif
if ( (vinfo.xres != width) || (vinfo.yres != height) ||
(vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) {
vinfo.activate = FB_ACTIVATE_NOW;
vinfo.accel_flags = 0;
vinfo.bits_per_pixel = bpp;
vinfo.xres = width;
vinfo.xres_virtual = width;
vinfo.yres = height;
if ( flags & SDL_DOUBLEBUF ) {
vinfo.yres_virtual = height*2;
} else {
vinfo.yres_virtual = height;
}
vinfo.xoffset = 0;
vinfo.yoffset = 0;
vinfo.red.length = vinfo.red.offset = 0;
vinfo.green.length = vinfo.green.offset = 0;
vinfo.blue.length = vinfo.blue.offset = 0;
vinfo.transp.length = vinfo.transp.offset = 0;
if ( ! choose_fbmodes_mode(&vinfo) ) {
choose_vesa_mode(&vinfo);
}
#ifdef FBCON_DEBUG
fprintf(stderr, "Printing wanted vinfo:\n");
print_vinfo(&vinfo);
#endif
if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
vinfo.yres_virtual = height;
if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
SDL_SetError("Couldn't set console screen info");
return(NULL);
}
}
} else {
int maxheight;
/* Figure out how much video memory is available */
if ( flags & SDL_DOUBLEBUF ) {
maxheight = height*2;
} else {
maxheight = height;
}
if ( vinfo.yres_virtual > maxheight ) {
vinfo.yres_virtual = maxheight;
}
}
cache_vinfo = vinfo;
#ifdef FBCON_DEBUG
fprintf(stderr, "Printing actual vinfo:\n");
print_vinfo(&vinfo);
#endif
Rmask = 0;
for ( i=0; i<vinfo.red.length; ++i ) {
Rmask <<= 1;
Rmask |= (0x00000001<<vinfo.red.offset);
}
Gmask = 0;
for ( i=0; i<vinfo.green.length; ++i ) {
Gmask <<= 1;
Gmask |= (0x00000001<<vinfo.green.offset);
}
Bmask = 0;
for ( i=0; i<vinfo.blue.length; ++i ) {
Bmask <<= 1;
Bmask |= (0x00000001<<vinfo.blue.offset);
}
if ( ! SDL_ReallocFormat(current, vinfo.bits_per_pixel,
Rmask, Gmask, Bmask, 0) ) {
return(NULL);
}
/* Get the fixed information about the console hardware.
This is necessary since finfo.line_length changes.
*/
if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
SDL_SetError("Couldn't get console hardware info");
return(NULL);
}
/* Save hardware palette, if needed */
FB_SavePalette(this, &finfo, &vinfo);
/* Set up the new mode framebuffer */
current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
current->w = vinfo.xres;
current->h = vinfo.yres;
current->pitch = finfo.line_length;
current->pixels = mapped_mem+mapped_offset;
/* Set up the information for hardware surfaces */
surfaces_mem = (char *)current->pixels +
vinfo.yres_virtual*current->pitch;
surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem));
FB_FreeHWSurfaces(this);
FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
/* Let the application know we have a hardware palette */
switch (finfo.visual) {
case FB_VISUAL_PSEUDOCOLOR:
current->flags |= SDL_HWPALETTE;
break;
default:
break;
}
/* Update for double-buffering, if we can */
if ( flags & SDL_DOUBLEBUF ) {
if ( vinfo.yres_virtual == (height*2) ) {
current->flags |= SDL_DOUBLEBUF;
flip_page = 0;
flip_address[0] = (char *)current->pixels;
flip_address[1] = (char *)current->pixels+
current->h*current->pitch;
this->screen = current;
FB_FlipHWSurface(this, current);
this->screen = NULL;
}
}
/* Set the update rectangle function */
this->UpdateRects = FB_DirectUpdate;
/* We're done */
return(current);
}
#ifdef FBCON_DEBUG
void FB_DumpHWSurfaces(_THIS)
{
vidmem_bucket *bucket;
printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
printf("\n");
printf(" Base Size\n");
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
printf("Bucket: %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
if ( bucket->prev ) {
if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
printf("Warning, corrupt bucket list! (prev)\n");
}
} else {
if ( bucket != &surfaces ) {
printf("Warning, corrupt bucket list! (!prev)\n");
}
}
if ( bucket->next ) {
if ( bucket->next->base != bucket->base+bucket->size ) {
printf("Warning, corrupt bucket list! (next)\n");
}
}
}
printf("\n");
}
#endif
static int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size)
{
vidmem_bucket *bucket;
surfaces_memtotal = size;
surfaces_memleft = size;
if ( surfaces_memleft > 0 ) {
bucket = (vidmem_bucket *)malloc(sizeof(*bucket));
if ( bucket == NULL ) {
SDL_OutOfMemory();
return(-1);
}
bucket->prev = &surfaces;
bucket->used = 0;
bucket->dirty = 0;
bucket->base = base;
bucket->size = size;
bucket->next = NULL;
} else {
bucket = NULL;
}
surfaces.prev = NULL;
surfaces.used = 1;
surfaces.dirty = 0;
surfaces.base = screen->pixels;
surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
surfaces.next = bucket;
screen->hwdata = (struct private_hwdata *)&surfaces;
return(0);
}
static void FB_FreeHWSurfaces(_THIS)
{
vidmem_bucket *bucket, *freeable;
bucket = surfaces.next;
while ( bucket ) {
freeable = bucket;
bucket = bucket->next;
free(freeable);
}
surfaces.next = NULL;
}
static int FB_AllocHWSurface(_THIS, SDL_Surface *surface)
{
vidmem_bucket *bucket;
int size;
int extra;
/* Temporarily, we only allow surfaces the same width as display.
Some blitters require the pitch between two hardware surfaces
to be the same. Others have interesting alignment restrictions.
Until someone who knows these details looks at the code...
*/
if ( surface->pitch > SDL_VideoSurface->pitch ) {
SDL_SetError("Surface requested wider than screen");
return(-1);
}
surface->pitch = SDL_VideoSurface->pitch;
size = surface->h * surface->pitch;
#ifdef FBCON_DEBUG
fprintf(stderr, "Allocating bucket of %d bytes\n", size);
#endif
/* Quick check for available mem */
if ( size > surfaces_memleft ) {
SDL_SetError("Not enough video memory");
return(-1);
}
/* Search for an empty bucket big enough */
for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
if ( ! bucket->used && (size <= bucket->size) ) {
break;
}
}
if ( bucket == NULL ) {
SDL_SetError("Video memory too fragmented");
return(-1);
}
/* Create a new bucket for left-over memory */
extra = (bucket->size - size);
if ( extra ) {
vidmem_bucket *newbucket;
#ifdef FBCON_DEBUG
fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
#endif
newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -