src/video/svga/SDL_svgavideo.c
author Sam Lantinga <slouken@lokigames.com>
Thu, 26 Apr 2001 16:45:43 +0000
changeset 0 74212992fb08
child 1 cf2af46e9e2a
permissions -rw-r--r--
Initial revision
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@devolution.com
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* SVGAlib based SDL video driver implementation.
    29 */
    30 
    31 #include <stdlib.h>
    32 #include <stdio.h>
    33 #include <unistd.h>
    34 #include <sys/stat.h>
    35 
    36 #if defined(linux)
    37 #include <linux/vt.h>
    38 #elif defined(__FreeBSD__)
    39 #include <sys/consio.h>
    40 #else
    41 #error You must choose your operating system here
    42 #endif
    43 #include <vga.h>
    44 #include <vgamouse.h>
    45 #include <vgakeyboard.h>
    46 
    47 #include "SDL.h"
    48 #include "SDL_error.h"
    49 #include "SDL_video.h"
    50 #include "SDL_mouse.h"
    51 #include "SDL_sysvideo.h"
    52 #include "SDL_pixels_c.h"
    53 #include "SDL_events_c.h"
    54 #include "SDL_svgavideo.h"
    55 #include "SDL_svgaevents_c.h"
    56 #include "SDL_svgamouse_c.h"
    57 
    58 
    59 /* Initialization/Query functions */
    60 static int SVGA_VideoInit(_THIS, SDL_PixelFormat *vformat);
    61 static SDL_Rect **SVGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
    62 static SDL_Surface *SVGA_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
    63 static int SVGA_SetColors(_THIS, int firstcolor, int ncolors,
    64 			  SDL_Color *colors);
    65 static void SVGA_VideoQuit(_THIS);
    66 
    67 /* Hardware surface functions */
    68 static int SVGA_AllocHWSurface(_THIS, SDL_Surface *surface);
    69 static int SVGA_LockHWSurface(_THIS, SDL_Surface *surface);
    70 static int SVGA_FlipHWSurface(_THIS, SDL_Surface *surface);
    71 static void SVGA_UnlockHWSurface(_THIS, SDL_Surface *surface);
    72 static void SVGA_FreeHWSurface(_THIS, SDL_Surface *surface);
    73 
    74 /* SVGAlib driver bootstrap functions */
    75 
    76 static int SVGA_Available(void)
    77 {
    78 	/* Check to see if we are root and stdin is a virtual console */
    79 	int console;
    80 
    81 	console = STDIN_FILENO;
    82 	if ( console >= 0 ) {
    83 		struct stat sb;
    84 		struct vt_mode dummy;
    85 
    86 		if ( (fstat(console, &sb) < 0) ||
    87 		     (ioctl(console, VT_GETMODE, &dummy) < 0) ) {
    88 			console = -1;
    89 		}
    90 	}
    91 	return((geteuid() == 0) && (console >= 0));
    92 }
    93 
    94 static void SVGA_DeleteDevice(SDL_VideoDevice *device)
    95 {
    96 	free(device->hidden);
    97 	free(device);
    98 }
    99 
   100 static SDL_VideoDevice *SVGA_CreateDevice(int devindex)
   101 {
   102 	SDL_VideoDevice *device;
   103 
   104 	/* Initialize all variables that we clean on shutdown */
   105 	device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
   106 	if ( device ) {
   107 		memset(device, 0, (sizeof *device));
   108 		device->hidden = (struct SDL_PrivateVideoData *)
   109 				malloc((sizeof *device->hidden));
   110 	}
   111 	if ( (device == NULL) || (device->hidden == NULL) ) {
   112 		SDL_OutOfMemory();
   113 		if ( device ) {
   114 			free(device);
   115 		}
   116 		return(0);
   117 	}
   118 	memset(device->hidden, 0, (sizeof *device->hidden));
   119 
   120 	/* Set the function pointers */
   121 	device->VideoInit = SVGA_VideoInit;
   122 	device->ListModes = SVGA_ListModes;
   123 	device->SetVideoMode = SVGA_SetVideoMode;
   124 	device->SetColors = SVGA_SetColors;
   125 	device->UpdateRects = NULL;
   126 	device->VideoQuit = SVGA_VideoQuit;
   127 	device->AllocHWSurface = SVGA_AllocHWSurface;
   128 	device->CheckHWBlit = NULL;
   129 	device->FillHWRect = NULL;
   130 	device->SetHWColorKey = NULL;
   131 	device->SetHWAlpha = NULL;
   132 	device->LockHWSurface = SVGA_LockHWSurface;
   133 	device->UnlockHWSurface = SVGA_UnlockHWSurface;
   134 	device->FlipHWSurface = NULL;
   135 	device->FreeHWSurface = SVGA_FreeHWSurface;
   136 	device->SetCaption = NULL;
   137 	device->SetIcon = NULL;
   138 	device->IconifyWindow = NULL;
   139 	device->GrabInput = NULL;
   140 	device->GetWMInfo = NULL;
   141 	device->InitOSKeymap = SVGA_InitOSKeymap;
   142 	device->PumpEvents = SVGA_PumpEvents;
   143 
   144 	device->free = SVGA_DeleteDevice;
   145 
   146 	return device;
   147 }
   148 
   149 VideoBootStrap SVGALIB_bootstrap = {
   150 	"svgalib", "SVGAlib",
   151 	SVGA_Available, SVGA_CreateDevice
   152 };
   153 
   154 static int SVGA_AddMode(_THIS, int mode, int actually_add, int force)
   155 {
   156 	vga_modeinfo *modeinfo;
   157 
   158 	modeinfo = vga_getmodeinfo(mode);
   159 	if ( force || ( modeinfo->flags & CAPABLE_LINEAR ) ) {
   160 		int i, j;
   161 
   162 		i = modeinfo->bytesperpixel-1;
   163 		if ( actually_add ) {
   164 			SDL_Rect saved_rect[2];
   165 			int      saved_mode[2];
   166 			int b;
   167 
   168 			/* Add the mode, sorted largest to smallest */
   169 			b = 0;
   170 			j = 0;
   171 			while ( (SDL_modelist[i][j]->w > modeinfo->width) ||
   172 			        (SDL_modelist[i][j]->h > modeinfo->height) ) {
   173 				++j;
   174 			}
   175 			/* Skip modes that are already in our list */
   176 			if ( (SDL_modelist[i][j]->w == modeinfo->width) &&
   177 			     (SDL_modelist[i][j]->h == modeinfo->height) ) {
   178 				return(0);
   179 			}
   180 			/* Insert the new mode */
   181 			saved_rect[b] = *SDL_modelist[i][j];
   182 			saved_mode[b] = SDL_vgamode[i][j];
   183 			SDL_modelist[i][j]->w = modeinfo->width;
   184 			SDL_modelist[i][j]->h = modeinfo->height;
   185 			SDL_vgamode[i][j] = mode;
   186 			/* Everybody scoot down! */
   187 			if ( saved_rect[b].w && saved_rect[b].h ) {
   188 			    for ( ++j; SDL_modelist[i][j]->w; ++j ) {
   189 				saved_rect[!b] = *SDL_modelist[i][j];
   190 				saved_mode[!b] = SDL_vgamode[i][j];
   191 				*SDL_modelist[i][j] = saved_rect[b];
   192 				SDL_vgamode[i][j] = saved_mode[b];
   193 				b = !b;
   194 			    }
   195 			    *SDL_modelist[i][j] = saved_rect[b];
   196 			    SDL_vgamode[i][j] = saved_mode[b];
   197 			}
   198 		} else {
   199 			++SDL_nummodes[i];
   200 		}
   201 	}
   202 	return( force || ( modeinfo->flags & CAPABLE_LINEAR ) );
   203 }
   204 
   205 static void SVGA_UpdateVideoInfo(_THIS)
   206 {
   207 	vga_modeinfo *modeinfo;
   208 
   209 	this->info.wm_available = 0;
   210 	this->info.hw_available = 1;
   211 	modeinfo = vga_getmodeinfo(vga_getcurrentmode());
   212 	this->info.video_mem = (modeinfo->maxpixels/1024);
   213 	if ( modeinfo->bytesperpixel > 0 ) {
   214 		this->info.video_mem *= modeinfo->bytesperpixel;
   215 	}
   216 	/* FIXME: Add hardware accelerated blit information */
   217 #if 0
   218 printf("Hardware accelerated blit: %savailable\n", modeinfo->haveblit ? "" : "not ");
   219 #endif
   220 }
   221 
   222 int SVGA_VideoInit(_THIS, SDL_PixelFormat *vformat)
   223 {
   224 	int keyboard;
   225 	int i, j;
   226 	int mode, total_modes;
   227 
   228 	/* Initialize all variables that we clean on shutdown */
   229 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   230 		SDL_nummodes[i] = 0;
   231 		SDL_modelist[i] = NULL;
   232 		SDL_vgamode[i] = NULL;
   233 	}
   234 
   235 	/* Initialize the library */
   236 	vga_disabledriverreport();
   237 	if ( vga_init() < 0 ) {
   238 		SDL_SetError("Unable to initialize SVGAlib");
   239 		return(-1);
   240 	}
   241 	vga_setmode(TEXT);
   242 
   243 	/* Enable mouse and keyboard support */
   244 	vga_setmousesupport(1);
   245 	keyboard = keyboard_init_return_fd();
   246 	if ( keyboard < 0 ) {
   247 		SDL_SetError("Unable to initialize keyboard");
   248 		return(-1);
   249 	}
   250 	if ( SVGA_initkeymaps(keyboard) < 0 ) {
   251 		return(-1);
   252 	}
   253 	keyboard_seteventhandler(SVGA_keyboardcallback);
   254 
   255 	/* Determine the screen depth (use default 8-bit depth) */
   256 	vformat->BitsPerPixel = 8;
   257 
   258 	/* Enumerate the available fullscreen modes */
   259 	total_modes = 0;
   260 	for ( mode=vga_lastmodenumber(); mode; --mode ) {
   261 		if ( vga_hasmode(mode) ) {
   262 			if ( SVGA_AddMode(this, mode, 0, 0) ) {
   263 				++total_modes;
   264 			}
   265 		}
   266 	}
   267 	if ( SVGA_AddMode(this, G320x200x256, 0, 1) ) ++total_modes;
   268 	if ( total_modes == 0 ) {
   269 		SDL_SetError("No linear video modes available");
   270 		return(-1);
   271 	}
   272 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   273 		SDL_vgamode[i] = (int *)malloc(SDL_nummodes[i]*sizeof(int));
   274 		if ( SDL_vgamode[i] == NULL ) {
   275 			SDL_OutOfMemory();
   276 			return(-1);
   277 		}
   278 		SDL_modelist[i] = (SDL_Rect **)
   279 				malloc((SDL_nummodes[i]+1)*sizeof(SDL_Rect *));
   280 		if ( SDL_modelist[i] == NULL ) {
   281 			SDL_OutOfMemory();
   282 			return(-1);
   283 		}
   284 		for ( j=0; j<SDL_nummodes[i]; ++j ) {
   285 			SDL_modelist[i][j]=(SDL_Rect *)malloc(sizeof(SDL_Rect));
   286 			if ( SDL_modelist[i][j] == NULL ) {
   287 				SDL_OutOfMemory();
   288 				return(-1);
   289 			}
   290 			memset(SDL_modelist[i][j], 0, sizeof(SDL_Rect));
   291 		}
   292 		SDL_modelist[i][j] = NULL;
   293 	}
   294 	for ( mode=vga_lastmodenumber(); mode; --mode ) {
   295 		if ( vga_hasmode(mode) ) {
   296 			SVGA_AddMode(this, mode, 1, 0);
   297 		}
   298 	}
   299 	SVGA_AddMode(this, G320x200x256, 1, 1);
   300 
   301 	/* Free extra (duplicated) modes */
   302 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   303 		j = 0;
   304 		while ( SDL_modelist[i][j] && SDL_modelist[i][j]->w ) {
   305 			j++;
   306 		}
   307 		while ( SDL_modelist[i][j] ) {
   308 			free(SDL_modelist[i][j]);
   309 			SDL_modelist[i][j] = NULL;
   310 			j++;
   311 		}
   312 	}
   313 
   314 	/* Fill in our hardware acceleration capabilities */
   315 	SVGA_UpdateVideoInfo(this);
   316 
   317 	/* We're done! */
   318 	return(0);
   319 }
   320 
   321 SDL_Rect **SVGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   322 {
   323 	return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
   324 }
   325 
   326 /* Various screen update functions available */
   327 static void SVGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
   328 static void SVGA_BankedUpdate(_THIS, int numrects, SDL_Rect *rects);
   329 
   330 SDL_Surface *SVGA_SetVideoMode(_THIS, SDL_Surface *current,
   331 				int width, int height, int bpp, Uint32 flags)
   332 {
   333 	int mode;
   334 	int vgamode;
   335 	vga_modeinfo *modeinfo;
   336 
   337 	/* Try to set the requested linear video mode */
   338 	bpp = (bpp+7)/8-1;
   339 	for ( mode=0; SDL_modelist[bpp][mode]; ++mode ) {
   340 		if ( (SDL_modelist[bpp][mode]->w == width) &&
   341 		     (SDL_modelist[bpp][mode]->h == height) ) {
   342 			break;
   343 		}
   344 	}
   345 	if ( SDL_modelist[bpp][mode] == NULL ) {
   346 		SDL_SetError("Couldn't find requested mode in list");
   347 		return(NULL);
   348 	}
   349 	vga_setmode(SDL_vgamode[bpp][mode]);
   350 	vga_setpage(0);
   351 
   352 	vgamode=SDL_vgamode[bpp][mode];
   353 	if ((vga_setlinearaddressing()<0) && (vgamode!=G320x200x256)) {
   354 		SDL_SetError("Unable to set linear addressing");
   355 		return(NULL);
   356 	}
   357 	modeinfo = vga_getmodeinfo(SDL_vgamode[bpp][mode]);
   358 
   359 	/* Update hardware acceleration info */
   360 	SVGA_UpdateVideoInfo(this);
   361 
   362 	/* Allocate the new pixel format for the screen */
   363 	bpp = (bpp+1)*8;
   364 	if ( (bpp == 16) && (modeinfo->colors == 32768) ) {
   365 		bpp = 15;
   366 	}
   367 	if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
   368 		return(NULL);
   369 	}
   370 
   371 	/* Set up the new mode framebuffer */
   372 	current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
   373 	current->w = width;
   374 	current->h = height;
   375 	current->pitch = modeinfo->linewidth;
   376 	current->pixels = vga_getgraphmem();
   377 
   378 	/* Set the blit function */
   379 	this->UpdateRects = SVGA_DirectUpdate;
   380 
   381 	/* Set up the mouse handler again (buggy SVGAlib 1.40) */
   382 	mouse_seteventhandler(SVGA_mousecallback);
   383 
   384 	/* We're done */
   385 	return(current);
   386 }
   387 
   388 /* We don't actually allow hardware surfaces other than the main one */
   389 static int SVGA_AllocHWSurface(_THIS, SDL_Surface *surface)
   390 {
   391 	return(-1);
   392 }
   393 static void SVGA_FreeHWSurface(_THIS, SDL_Surface *surface)
   394 {
   395 	return;
   396 }
   397 
   398 /* We need to wait for vertical retrace on page flipped displays */
   399 static int SVGA_LockHWSurface(_THIS, SDL_Surface *surface)
   400 {
   401 	if ( (surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
   402 		vga_waitretrace();
   403 	}
   404 	return(0);
   405 }
   406 static void SVGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
   407 {
   408 	return;
   409 }
   410 
   411 /* FIXME: How is this done with SVGAlib? */
   412 static int SVGA_FlipHWSurface(_THIS, SDL_Surface *surface)
   413 {
   414 	return(0);
   415 }
   416 
   417 static void SVGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
   418 {
   419 	return;
   420 }
   421 
   422 /* FIXME: Can this be used under SVGAlib? */
   423 static void SVGA_BankedUpdate(_THIS, int numrects, SDL_Rect *rects)
   424 {
   425 	return;
   426 }
   427 
   428 int SVGA_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   429 {
   430         int i;
   431 
   432 	for(i = 0; i < ncolors; i++) {
   433 	        vga_setpalette(firstcolor + i,
   434 			       colors[i].r>>2,
   435 			       colors[i].g>>2,
   436 			       colors[i].b>>2);
   437 	}
   438 	return(1);
   439 }
   440 
   441 /* Note:  If we are terminated, this could be called in the middle of
   442    another SDL video routine -- notably UpdateRects.
   443 */
   444 void SVGA_VideoQuit(_THIS)
   445 {
   446 	int i, j;
   447 
   448 	/* Reset the console video mode */
   449 	if ( this->screen && (this->screen->w && this->screen->h) ) {
   450 		vga_setmode(TEXT);
   451 	}
   452 	keyboard_close();
   453 
   454 	/* Free video mode lists */
   455 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   456 		if ( SDL_modelist[i] != NULL ) {
   457 			for ( j=0; SDL_modelist[i][j]; ++j )
   458 				free(SDL_modelist[i][j]);
   459 			free(SDL_modelist[i]);
   460 			SDL_modelist[i] = NULL;
   461 		}
   462 		if ( SDL_vgamode[i] != NULL ) {
   463 			free(SDL_vgamode[i]);
   464 			SDL_vgamode[i] = NULL;
   465 		}
   466 	}
   467 	if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) {
   468 		/* Direct screen access, no memory buffer */
   469 		this->screen->pixels = NULL;
   470 	}
   471 }