Import VOSF from Basilisk II for faster and more accurate video refresh.

There may be some bugs left though. Rework sigsegv_handler() a little to
accomodate VOSF way of life.

TODO: merge video drivers infrastructure from B2.
This commit is contained in:
gbeauche 2003-05-22 22:12:05 +00:00
parent d29a00c17f
commit 9e7670c922
8 changed files with 264 additions and 55 deletions

View File

@ -58,7 +58,8 @@ links:
Unix/sshpty.h Unix/sshpty.c Unix/strlcpy.h Unix/strlcpy.c \
Unix/sys_unix.cpp Unix/timer_unix.cpp Unix/xpram_unix.cpp \
Unix/sigsegv.h Unix/sigsegv.cpp Unix/vm_alloc.h Unix/vm_alloc.cpp \
Unix/posix_sem.cpp \
Unix/posix_sem.cpp Unix/video_vosf.h Unix/video_blit.h \
Unix/video_blit.cpp \
Unix/Linux/scsi_linux.cpp Unix/Linux/NetDriver'; \
PREFIX="`pwd`/"; case $(B2_TOPDIR) in /*) PREFIX="";; esac; \
for i in $$list; do \

View File

@ -29,7 +29,8 @@ SRCS = main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp sys_unix.cpp
../rom_patches.cpp ../rsrc_patches.cpp ../emul_op.cpp ../name_registry.cpp \
../macos_util.cpp ../timer.cpp timer_unix.cpp ../xpram.cpp xpram_unix.cpp \
../adb.cpp clip_unix.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \
Linux/scsi_linux.cpp ../video.cpp video_x.cpp ../audio.cpp audio_oss_esd.cpp ../ether.cpp \
Linux/scsi_linux.cpp ../video.cpp video_blit.cpp video_x.cpp \
../audio.cpp audio_oss_esd.cpp ../ether.cpp \
Linux/ether_linux.cpp ../serial.cpp serial_unix.cpp ../extfs.cpp extfs_unix.cpp \
about_window_unix.cpp ../user_strings.cpp user_strings_unix.cpp \
vm_alloc.cpp sigsegv.cpp \

View File

@ -8,6 +8,7 @@ AC_CONFIG_HEADER(config.h)
dnl Options.
AC_ARG_ENABLE(xf86-dga, [ --enable-xf86-dga use the XFree86 DGA extension [default=yes]], [WANT_XF86_DGA=$enableval], [WANT_XF86_DGA=yes])
AC_ARG_ENABLE(xf86-vidmode, [ --enable-xf86-vidmode use the XFree86 VidMode extension [default=yes]], [WANT_XF86_VIDMODE=$enableval], [WANT_XF86_VIDMODE=yes])
AC_ARG_ENABLE(vosf, [ --enable-vosf enable video on SEGV signals [default=yes]], [WANT_VOSF=$enableval], [WANT_VOSF=yes])
AC_ARG_WITH(esd, [ --with-esd support ESD for sound under Linux/FreeBSD [default=yes]], [WANT_ESD=$withval], [WANT_ESD=yes])
AC_ARG_WITH(gtk, [ --with-gtk use GTK user interface [default=yes]], [WANT_GTK=$withval], [WANT_GTK=yes])
AC_ARG_WITH(mon, [ --with-mon use mon as debugger [default=yes]], [WANT_MON=$withval], [WANT_MON=yes])
@ -477,6 +478,19 @@ AC_CACHE_CHECK([whether we can skip instruction in SIGSEGV handler],
AC_TRANSLATE_DEFINE(HAVE_SIGSEGV_SKIP_INSTRUCTION, "$ac_cv_have_skip_instruction",
[Define if we can ignore the fault (instruction skipping in SIGSEGV handler).])
dnl Can we do Video on SEGV Signals ?
CAN_VOSF=no
if [[ "$ac_cv_have_extended_signals" = "yes" -o "$ac_cv_have_sigcontext_hack" = "yes" ]]; then
CAN_VOSF=yes
fi
dnl Enable VOSF screen updates with this feature is requested and feasible
if [[ "x$WANT_VOSF" = "xyes" -a "x$CAN_VOSF" = "xyes" ]]; then
AC_DEFINE(ENABLE_VOSF, 1, [Define if using video enabled on SEGV signals.])
else
WANT_VOSF=no
fi
dnl Generate Makefile.
AC_SUBST(SYSSRCS)
AC_OUTPUT(Makefile)
@ -487,6 +501,7 @@ echo SheepShaver configuration summary:
echo
echo XFree86 DGA support .............. : $WANT_XF86_DGA
echo XFree86 VidMode support .......... : $WANT_XF86_VIDMODE
echo Enable video on SEGV signals ..... : $WANT_VOSF
echo ESD sound support ................ : $WANT_ESD
echo GTK user interface ............... : $WANT_GTK
echo mon debugger support ............. : $WANT_MON

View File

@ -108,6 +108,7 @@
#include "rom_patches.h"
#include "user_strings.h"
#include "vm_alloc.h"
#include "sigsegv.h"
#define DEBUG 0
#include "debug.h"
@ -1282,21 +1283,23 @@ static void sigusr2_handler(int sig, sigcontext_struct *sc)
static void sigsegv_handler(int sig, sigcontext_struct *sc)
{
pt_regs *r = sc->regs;
// Get effective address
uint32 addr = r->dar;
#if ENABLE_VOSF
// Handle screen fault.
extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction);
if (Screen_fault_handler((sigsegv_address_t)addr, (sigsegv_address_t)r->nip))
return;
#endif
num_segv++;
// Fault in Mac ROM or RAM?
bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize));
if (mac_fault) {
// Get opcode and divide into fields
uint32 opcode = *((uint32 *)r->nip);
uint32 primop = opcode >> 26;
uint32 exop = (opcode >> 1) & 0x3ff;
uint32 ra = (opcode >> 16) & 0x1f;
uint32 rb = (opcode >> 11) & 0x1f;
uint32 rd = (opcode >> 21) & 0x1f;
int32 imm = (int16)(opcode & 0xffff);
// "VM settings" during MacOS 8 installation
if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) {
r->nip += 4;
@ -1324,6 +1327,15 @@ static void sigsegv_handler(int sig, sigcontext_struct *sc)
return;
}
// Get opcode and divide into fields
uint32 opcode = *((uint32 *)r->nip);
uint32 primop = opcode >> 26;
uint32 exop = (opcode >> 1) & 0x3ff;
uint32 ra = (opcode >> 16) & 0x1f;
uint32 rb = (opcode >> 11) & 0x1f;
uint32 rd = (opcode >> 21) & 0x1f;
int32 imm = (int16)(opcode & 0xffff);
// Analyze opcode
enum {
TYPE_UNKNOWN,
@ -1407,27 +1419,6 @@ static void sigsegv_handler(int sig, sigcontext_struct *sc)
transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
}
// Calculate effective address
uint32 addr = 0;
switch (addr_mode) {
case MODE_X:
case MODE_UX:
if (ra == 0)
addr = r->gpr[rb];
else
addr = r->gpr[ra] + r->gpr[rb];
break;
case MODE_NORM:
case MODE_U:
if (ra == 0)
addr = (int32)(int16)imm;
else
addr = r->gpr[ra] + (int32)(int16)imm;
break;
default:
break;
}
// Ignore ROM writes
if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) {
// D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->nip));

View File

@ -59,6 +59,9 @@
# endif
#endif
// Mac and host address space are the same
#define REAL_ADDRESSING 1
// Are we using a PPC emulator or the real thing?
#ifdef __powerpc__
#define EMULATED_PPC 0

View File

@ -62,6 +62,7 @@ user_string_def platform_strings[] = {
{STR_HELP_MENU_GTK, "/_Help"},
{STR_HELP_ITEM_ABOUT_GTK, "/Help/_About SheepShaver"},
{STR_SUSPEND_WINDOW_TITLE, "SheepShaver suspended. Press Space to reactivate."},
{STR_VOSF_INIT_ERR, "Cannot initialize Video on SEGV signals."},
{-1, NULL} // End marker
};

View File

@ -52,7 +52,8 @@ enum {
STR_PREFS_ITEM_QUIT_GTK,
STR_HELP_MENU_GTK,
STR_HELP_ITEM_ABOUT_GTK,
STR_SUSPEND_WINDOW_TITLE
STR_SUSPEND_WINDOW_TITLE,
STR_VOSF_INIT_ERR
};
#endif

View File

@ -58,6 +58,12 @@ static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req
static bool has_dga = false; // Flag: Video DGA capable
static bool has_vidmode = false; // Flag: VidMode extension available
#ifdef ENABLE_VOSF
static bool use_vosf = true; // Flag: VOSF enabled
#else
static const bool use_vosf = false; // VOSF not possible
#endif
static bool palette_changed = false; // Flag: Palette changed, redraw thread must update palette
static bool ctrl_down = false; // Flag: Ctrl key pressed
static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread
@ -92,8 +98,9 @@ static Cursor mac_cursor;
static GC cursor_gc, cursor_mask_gc;
static bool cursor_changed = false; // Flag: Cursor changed, window_func must update cursor
static bool have_shm = false; // Flag: SHM present and usable
static uint8 *the_buffer; // Pointer to Mac frame buffer
static uint8 *the_buffer = NULL; // Pointer to Mac frame buffer
static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer
static uint32 the_buffer_size; // Size of allocated the_buffer
// Variables for DGA mode
static char *dga_screen_base;
@ -118,6 +125,12 @@ extern Display *x_display;
extern void SysMountFirstFloppy(void);
// Video acceleration through SIGSEGV
#ifdef ENABLE_VOSF
# include "video_vosf.h"
#endif
/*
* Open display (window or fullscreen)
*/
@ -138,6 +151,9 @@ static int error_handler(Display *d, XErrorEvent *e)
// Open window
static bool open_window(int width, int height)
{
int aligned_width = (width + 15) & ~15;
int aligned_height = (height + 15) & ~15;
// Set absolute mouse mode
ADBSetRelMouseMode(false);
@ -186,9 +202,8 @@ static bool open_window(int width, int height)
// Create SHM image ("height + 2" for safety)
img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
screen_base = (uint32)shmat(shminfo.shmid, 0, 0);
the_buffer = (uint8 *)screen_base;
shminfo.shmaddr = img->data = (char *)screen_base;
the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
shminfo.shmaddr = img->data = (char *)the_buffer_copy;
shminfo.readOnly = False;
// Try to attach SHM image, catching errors
@ -209,7 +224,7 @@ static bool open_window(int width, int height)
// Create normal X image if SHM doesn't work ("height + 2" for safety)
if (!have_shm) {
int bytes_per_row = width;
int bytes_per_row = aligned_width;
switch (depth) {
case 1:
bytes_per_row /= 8;
@ -223,9 +238,8 @@ static bool open_window(int width, int height)
bytes_per_row *= 4;
break;
}
screen_base = (uint32)malloc((height + 2) * bytes_per_row);
the_buffer = (uint8 *)screen_base;
img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)screen_base, width, height, 32, bytes_per_row);
the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
img = XCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row);
}
// 1-Bit mode is big-endian
@ -234,8 +248,20 @@ static bool open_window(int width, int height)
img->bitmap_bit_order = MSBFirst;
}
// Allocate memory for frame buffer copy
the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line);
#ifdef ENABLE_VOSF
use_vosf = true;
// Allocate memory for frame buffer (SIZE is extended to page-boundary)
the_host_buffer = the_buffer_copy;
the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
the_buffer = (uint8 *)vm_acquire(the_buffer_size);
the_buffer_copy = (uint8 *)malloc(the_buffer_size);
D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
#else
// Allocate memory for frame buffer
the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
#endif
screen_base = (uint32)the_buffer;
// Create GC
the_gc = XCreateGC(x_display, the_win, 0, 0);
@ -255,6 +281,17 @@ static bool open_window(int width, int height)
mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0);
cursor_changed = false;
// Init blitting routines
bool native_byte_order;
#ifdef WORDS_BIGENDIAN
native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
#else
native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
#endif
#ifdef ENABLE_VOSF
Screen_blitter_init(&visualInfo, native_byte_order, depth);
#endif
// Set bytes per row
VModes[cur_mode].viRowBytes = img->bytes_per_line;
XSync(x_display, false);
@ -289,7 +326,6 @@ static bool open_dga(int width, int height)
XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
XF86DGASetViewPort(x_display, screen, 0, 0);
XF86DGASetVidPage(x_display, screen, 0);
screen_base = (uint32)dga_screen_base;
// Set colormap
if (depth == 8)
@ -307,6 +343,33 @@ static bool open_dga(int width, int height)
bytes_per_row *= 4;
break;
}
#if ENABLE_VOSF
bool native_byte_order;
#ifdef WORDS_BIGENDIAN
native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
#else
native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
#endif
#if REAL_ADDRESSING || DIRECT_ADDRESSING
// Screen_blitter_init() returns TRUE if VOSF is mandatory
// i.e. the framebuffer update function is not Blit_Copy_Raw
use_vosf = Screen_blitter_init(&visualInfo, native_byte_order, depth);
if (use_vosf) {
// Allocate memory for frame buffer (SIZE is extended to page-boundary)
the_host_buffer = the_buffer;
the_buffer_size = page_extend((height + 2) * bytes_per_row);
the_buffer_copy = (uint8 *)malloc(the_buffer_size);
the_buffer = (uint8 *)vm_acquire(the_buffer_size);
}
#else
use_vosf = false;
the_buffer = dga_screen_base;
#endif
#endif
screen_base = (uint32)the_buffer;
VModes[cur_mode].viRowBytes = bytes_per_row;
XSync(x_display, false);
return true;
@ -339,12 +402,24 @@ static bool open_display(void)
depth = 32;
break;
}
bool display_open = false;
if (display_type == DIS_SCREEN)
return open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
display_open = open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
else if (display_type == DIS_WINDOW)
return open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
else
return false;
display_open = open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
#ifdef ENABLE_VOSF
if (use_vosf) {
// Initialize the VOSF system
if (!video_vosf_init()) {
ErrorAlert(GetString(STR_VOSF_INIT_ERR));
return false;
}
}
#endif
return display_open;
}
@ -355,14 +430,28 @@ static bool open_display(void)
// Close window
static void close_window(void)
{
if (have_shm) {
XShmDetach(x_display, &shminfo);
#ifdef ENABLE_VOSF
the_host_buffer = NULL; // don't free() in driver_base dtor
#else
the_buffer_copy = NULL; // don't free() in driver_base dtor
#endif
}
if (img) {
if (!have_shm)
img->data = NULL;
XDestroyImage(img);
}
if (have_shm) {
shmdt(shminfo.shmaddr);
shmctl(shminfo.shmid, IPC_RMID, 0);
}
if (the_gc)
XFreeGC(x_display, the_gc);
// Close window
XDestroyWindow(x_display, the_win);
// Close frame buffer copy
if (the_buffer_copy) {
free(the_buffer_copy);
the_buffer_copy = NULL;
}
}
// Close DGA mode
@ -378,6 +467,17 @@ static void close_dga(void)
if (has_vidmode)
XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
#endif
if (!use_vosf) {
// don't free() the screen buffer in driver_base dtor
the_buffer = NULL;
}
#ifdef ENABLE_VOSF
else {
// don't free() the screen buffer in driver_base dtor
the_host_buffer = NULL;
}
#endif
}
static void close_display(void)
@ -386,6 +486,41 @@ static void close_display(void)
close_dga();
else if (display_type == DIS_WINDOW)
close_window();
#ifdef ENABLE_VOSF
if (use_vosf) {
// Deinitialize VOSF
video_vosf_exit();
}
#endif
// Free frame buffer(s)
if (!use_vosf) {
if (the_buffer_copy) {
free(the_buffer_copy);
the_buffer_copy = NULL;
}
}
#ifdef ENABLE_VOSF
else {
// the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
if (the_buffer != VM_MAP_FAILED) {
D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
vm_release(the_buffer, the_buffer_size);
the_buffer = NULL;
}
if (the_host_buffer) {
D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
free(the_host_buffer);
the_host_buffer = NULL;
}
if (the_buffer_copy) {
D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
free(the_buffer_copy);
the_buffer_copy = NULL;
}
}
#endif
}
@ -456,6 +591,12 @@ static bool has_mode(int x, int y)
bool VideoInit(void)
{
#ifdef ENABLE_VOSF
// Zero the mainBuffer structure
mainBuffer.dirtyPages = NULL;
mainBuffer.pageInfo = NULL;
#endif
// Init variables
private_data = NULL;
cur_mode = 0; // Window 640x480
@ -652,6 +793,13 @@ void VideoExit(void)
redraw_thread_active = false;
}
#ifdef ENABLE_VOSF
if (use_vosf) {
// Deinitialize VOSF
video_vosf_exit();
}
#endif
// Close window and server connection
if (x_display != NULL) {
XSync(x_display, false);
@ -729,8 +877,24 @@ static void resume_emul(void)
XF86DGASetViewPort(x_display, screen, 0, 0);
XSync(x_display, false);
// the_buffer already contains the data to restore. i.e. since a temporary
// frame buffer is used when VOSF is actually used, fb_save is therefore
// not necessary.
#ifdef ENABLE_VOSF
if (use_vosf) {
LOCK_VOSF;
PFLAG_SET_ALL;
UNLOCK_VOSF;
memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
}
#endif
// Restore frame buffer
if (fb_save) {
#ifdef ENABLE_VOSF
// Don't copy fb_save to the temporary frame buffer in VOSF mode
if (!use_vosf)
#endif
memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
free(fb_save);
fb_save = NULL;
@ -979,6 +1143,13 @@ static void handle_events(void)
// Hidden parts exposed, force complete refresh
case Expose:
#ifdef ENABLE_VOSF
if (use_vosf) { // VOSF refresh
LOCK_VOSF;
PFLAG_SET_ALL;
UNLOCK_VOSF;
}
#endif
memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
break;
}
@ -1376,7 +1547,18 @@ static void *redraw_func(void *arg)
tick_counter = 0;
// Update display
update_display();
#ifdef ENABLE_VOSF
if (use_vosf) {
if (mainBuffer.dirty) {
LOCK_VOSF;
update_display_window_vosf();
UNLOCK_VOSF;
XSync(x_display, false); // Let the server catch up
}
}
else
#endif
update_display();
// Set new cursor image if it was changed
if (cursor_changed) {
@ -1391,6 +1573,20 @@ static void *redraw_func(void *arg)
}
}
}
#ifdef ENABLE_VOSF
else if (use_vosf) {
// Update display (VOSF variant)
static int tick_counter = 0;
if (++tick_counter >= frame_skip) {
tick_counter = 0;
if (mainBuffer.dirty) {
LOCK_VOSF;
update_display_dga_vosf();
UNLOCK_VOSF;
}
}
}
#endif
// Set new palette if it was changed
if (palette_changed && !emul_suspended) {