From 2431bf5e1da81eb388f9b0a60af0fc2796e99eba Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 8 May 2006 05:33:02 +0000 Subject: [PATCH] Fixed bug #49 Added support for non-blocking VT switching on the framebuffer console. --- src/video/fbcon/SDL_fb3dfx.c | 6 ++ src/video/fbcon/SDL_fbevents.c | 102 ++++++++++++++++++--------------- src/video/fbcon/SDL_fbmatrox.c | 6 ++ src/video/fbcon/SDL_fbriva.c | 6 ++ src/video/fbcon/SDL_fbvideo.c | 28 ++++----- src/video/fbcon/SDL_fbvideo.h | 10 ++++ 6 files changed, 94 insertions(+), 64 deletions(-) diff --git a/src/video/fbcon/SDL_fb3dfx.c b/src/video/fbcon/SDL_fb3dfx.c index 36cada54d..dca9f7339 100644 --- a/src/video/fbcon/SDL_fb3dfx.c +++ b/src/video/fbcon/SDL_fb3dfx.c @@ -57,6 +57,9 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) int dstX, dstY; /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } @@ -102,6 +105,9 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, Uint32 use_colorkey; /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } diff --git a/src/video/fbcon/SDL_fbevents.c b/src/video/fbcon/SDL_fbevents.c index a3985665a..02a4854fa 100644 --- a/src/video/fbcon/SDL_fbevents.c +++ b/src/video/fbcon/SDL_fbevents.c @@ -209,6 +209,8 @@ int FB_EnterGraphicsMode(_THIS) SDL_SetError("Unable to set keyboard in graphics mode"); return(-1); } + /* Prevent switching the virtual terminal */ + ioctl(keyboard_fd, VT_LOCKSWITCH, 1); } return(keyboard_fd); } @@ -222,6 +224,7 @@ void FB_LeaveGraphicsMode(_THIS) saved_kbd_mode = -1; /* Head back over to the original virtual terminal */ + ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1); if ( saved_vt > 0 ) { ioctl(keyboard_fd, VT_ACTIVATE, saved_vt); } @@ -456,7 +459,7 @@ static int set_imps2_mode(int fd) {0xFF} */ Uint8 set_imps2[] = {0xf3, 200, 0xf3, 100, 0xf3, 80}; - Uint8 reset = 0xff; + /*Uint8 reset = 0xff;*/ fd_set fdset; struct timeval tv; int retval = 0; @@ -916,65 +919,60 @@ static void handle_mouse(_THIS) return; } -/* Handle switching to another VC, returns when our VC is back. - This isn't necessarily the best solution. For SDL 1.3 we need - a way of notifying the application when we lose access to the - video hardware and when we regain it. - */ +/* Handle switching to another VC, returns when our VC is back */ +static void switch_vt_prep(_THIS) +{ + SDL_Surface *screen = SDL_VideoSurface; + + SDL_PrivateAppActive(0, (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS)); + + /* Save the contents of the screen, and go to text mode */ + wait_idle(this); + screen_arealen = ((screen->h + (2*this->offset_y)) * screen->pitch); + screen_contents = (Uint8 *)SDL_malloc(screen_arealen); + if ( screen_contents ) { + SDL_memcpy(screen_contents, screen->pixels, screen_arealen); + } + FB_SavePaletteTo(this, 256, screen_palette); + ioctl(console_fd, FBIOGET_VSCREENINFO, &screen_vinfo); + ioctl(keyboard_fd, KDSETMODE, KD_TEXT); + ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1); +} +static void switch_vt_done(_THIS) +{ + SDL_Surface *screen = SDL_VideoSurface; + + /* Restore graphics mode and the contents of the screen */ + ioctl(keyboard_fd, VT_LOCKSWITCH, 1); + ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS); + ioctl(console_fd, FBIOPUT_VSCREENINFO, &screen_vinfo); + FB_RestorePaletteFrom(this, 256, screen_palette); + if ( screen_contents ) { + SDL_memcpy(screen->pixels, screen_contents, screen_arealen); + SDL_free(screen_contents); + screen_contents = NULL; + } + + SDL_PrivateAppActive(1, (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS)); +} static void switch_vt(_THIS, unsigned short which) { - struct fb_var_screeninfo vinfo; struct vt_stat vtstate; - unsigned short v_active; - __u16 saved_pal[3*256]; - SDL_Surface *screen; - Uint32 screen_arealen; - Uint8 *screen_contents = NULL; /* Figure out whether or not we're switching to a new console */ if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) < 0) || (which == vtstate.v_active) ) { return; } - v_active = vtstate.v_active; - - /* Save the contents of the screen, and go to text mode */ - SDL_mutexP(hw_lock); - wait_idle(this); - screen = SDL_VideoSurface; - if ( !SDL_ShadowSurface ) { - screen_arealen = (screen->h*screen->pitch); - screen_contents = (Uint8 *)SDL_malloc(screen_arealen); - if ( screen_contents ) { - SDL_memcpy(screen_contents, (Uint8 *)screen->pixels + screen->offset, screen_arealen); - } - } - FB_SavePaletteTo(this, 256, saved_pal); - ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo); - ioctl(keyboard_fd, KDSETMODE, KD_TEXT); /* New console, switch to it */ + SDL_mutexP(hw_lock); + switch_vt_prep(this); if ( ioctl(keyboard_fd, VT_ACTIVATE, which) == 0 ) { - /* Wait for our console to be activated again */ ioctl(keyboard_fd, VT_WAITACTIVE, which); - while ( ioctl(keyboard_fd, VT_WAITACTIVE, v_active) < 0 ) { - if ( (errno != EINTR) && (errno != EAGAIN) ) { - /* Unknown VT error - cancel this */ - break; - } - SDL_Delay(500); - } - } - - /* Restore graphics mode and the contents of the screen */ - ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS); - ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo); - FB_RestorePaletteFrom(this, 256, saved_pal); - if ( screen_contents ) { - SDL_memcpy((Uint8 *)screen->pixels + screen->offset, screen_contents, screen_arealen); - SDL_free(screen_contents); + switched_away = 1; } else { - SDL_UpdateRect(screen, 0, 0, 0, 0); + switch_vt_done(this); } SDL_mutexV(hw_lock); } @@ -1032,6 +1030,18 @@ void FB_PumpEvents(_THIS) static struct timeval zero; do { + if ( switched_away ) { + struct vt_stat vtstate; + + SDL_mutexP(hw_lock); + if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0) && + vtstate.v_active == current_vt ) { + switched_away = 0; + switch_vt_done(this); + } + SDL_mutexV(hw_lock); + } + posted = 0; FD_ZERO(&fdset); diff --git a/src/video/fbcon/SDL_fbmatrox.c b/src/video/fbcon/SDL_fbmatrox.c index 84ea89885..177131a71 100644 --- a/src/video/fbcon/SDL_fbmatrox.c +++ b/src/video/fbcon/SDL_fbmatrox.c @@ -70,6 +70,9 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) Uint32 fillop; /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } @@ -132,6 +135,9 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, } /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } diff --git a/src/video/fbcon/SDL_fbriva.c b/src/video/fbcon/SDL_fbriva.c index 9ba611bcd..1a712dce0 100644 --- a/src/video/fbcon/SDL_fbriva.c +++ b/src/video/fbcon/SDL_fbriva.c @@ -77,6 +77,9 @@ static int FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) RivaBitmap *Bitmap = (RivaBitmap *)(mapped_io + BITMAP_OFFSET); /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } @@ -120,6 +123,9 @@ static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect, } /* Don't blit to the display surface when switched away */ + if ( switched_away ) { + return -2; /* no hardware access */ + } if ( dst == this->screen ) { SDL_mutexP(hw_lock); } diff --git a/src/video/fbcon/SDL_fbvideo.c b/src/video/fbcon/SDL_fbvideo.c index 098ae89e8..bdbcfbd5d 100644 --- a/src/video/fbcon/SDL_fbvideo.c +++ b/src/video/fbcon/SDL_fbvideo.c @@ -1238,26 +1238,10 @@ static void FB_FreeHWSurface(_THIS, SDL_Surface *surface) surface->hwdata = NULL; } -/* Routine to check to see if the frame buffer virtual terminal */ -/* is the current(active) one. If it is not, result will cause */ -/* Lock to fail. (would have waited forever, since the fbevent */ -/* keyboard handler maintains a lock when switched away from */ -/* current) */ -static __inline__ int FB_IsFrameBufferActive(_THIS) -{ - struct vt_stat vtstate; - if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) < 0) || - (current_vt != vtstate.v_active) ) { - return 0; - } - return 1; -} - - static int FB_LockHWSurface(_THIS, SDL_Surface *surface) { - if ( !FB_IsFrameBufferActive(this) ) { - return -1; /* fail locking. */ + if ( switched_away ) { + return -2; /* no hardware access */ } if ( surface == this->screen ) { SDL_mutexP(hw_lock); @@ -1293,6 +1277,10 @@ static void FB_WaitIdle(_THIS) static int FB_FlipHWSurface(_THIS, SDL_Surface *surface) { + if ( switched_away ) { + return -2; /* no hardware access */ + } + /* Wait for vertical retrace and then flip display */ cache_vinfo.yoffset = flip_page*surface->h; if ( FB_IsSurfaceBusy(this->screen) ) { @@ -1333,6 +1321,10 @@ static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects) Uint32 *src, *srcPtr; Uint8 *dst, *dstPtr; + if ( switched_away ) { + return; /* no hardware access */ + } + screen = this->screen; FBPitch = screen->w >> 3; SRCPitch = screen->pitch >> 2; diff --git a/src/video/fbcon/SDL_fbvideo.h b/src/video/fbcon/SDL_fbvideo.h index f03b1024d..8a8fa10f0 100644 --- a/src/video/fbcon/SDL_fbvideo.h +++ b/src/video/fbcon/SDL_fbvideo.h @@ -85,6 +85,11 @@ struct SDL_PrivateVideoData { int surfaces_memleft; SDL_mutex *hw_lock; + int switched_away; + struct fb_var_screeninfo screen_vinfo; + Uint32 screen_arealen; + Uint8 *screen_contents; + __u16 screen_palette[3*256]; void (*wait_vbl)(_THIS); void (*wait_idle)(_THIS); @@ -117,6 +122,11 @@ struct SDL_PrivateVideoData { #define surfaces_memtotal (this->hidden->surfaces_memtotal) #define surfaces_memleft (this->hidden->surfaces_memleft) #define hw_lock (this->hidden->hw_lock) +#define switched_away (this->hidden->switched_away) +#define screen_vinfo (this->hidden->screen_vinfo) +#define screen_arealen (this->hidden->screen_arealen) +#define screen_contents (this->hidden->screen_contents) +#define screen_palette (this->hidden->screen_palette) #define wait_vbl (this->hidden->wait_vbl) #define wait_idle (this->hidden->wait_idle)