From 0cf3f32b7d98e05de222d24f99b635f81ee58ff8 Mon Sep 17 00:00:00 2001 From: cebix <> Date: Thu, 28 Jun 2001 21:20:02 +0000 Subject: [PATCH] video_x.cpp supports resolution switching in windowed mode: the available resolutions are 512x384, 640x480, 800x600, 1024x768 and 1280x1024 (the prefs editor has to be updated to reflect this). The resolution selected in the prefs editor is used as the default, but it can be changed in the Monitors control panel. So far only tested with direct addressing. --- BasiliskII/TODO | 2 +- BasiliskII/src/Unix/main_unix.cpp | 3 +- BasiliskII/src/Unix/user_strings_unix.cpp | 1 + BasiliskII/src/Unix/user_strings_unix.h | 1 + BasiliskII/src/Unix/video_vosf.h | 213 +++++++- BasiliskII/src/Unix/video_x.cpp | 631 ++++++++-------------- BasiliskII/src/include/video.h | 43 +- BasiliskII/src/include/video_defs.h | 38 +- BasiliskII/src/slot_rom.cpp | 76 +-- BasiliskII/src/uae_cpu/basilisk_glue.cpp | 11 + BasiliskII/src/uae_cpu/cpu_emulation.h | 9 +- BasiliskII/src/uae_cpu/cpuopti.c | 6 +- BasiliskII/src/uae_cpu/memory.cpp | 15 +- BasiliskII/src/video.cpp | 257 ++++++--- 14 files changed, 750 insertions(+), 556 deletions(-) diff --git a/BasiliskII/TODO b/BasiliskII/TODO index a5914a23..b23d2eda 100644 --- a/BasiliskII/TODO +++ b/BasiliskII/TODO @@ -12,7 +12,7 @@ General: ReadISRC/ReadAudio/ReadAllSubcodes - Sound output rate/bits/channels switching - Sound in -- Video: gamma tables, resolution/depth switching, multiple monitor support +- Video: gamma tables, multiple monitor support - More accurate Time Manager - Serial driver: XOn/XOff handshaking - Classic ROM: mouse button/movement is broken with ROM mouse handler diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index 393f3bea..997725ca 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -667,11 +667,10 @@ static void sigint_handler(...) uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); -#else +#endif char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); QuitEmulator(); -#endif } #endif diff --git a/BasiliskII/src/Unix/user_strings_unix.cpp b/BasiliskII/src/Unix/user_strings_unix.cpp index 1602af8e..cfafdaa4 100644 --- a/BasiliskII/src/Unix/user_strings_unix.cpp +++ b/BasiliskII/src/Unix/user_strings_unix.cpp @@ -37,6 +37,7 @@ user_string_def platform_strings[] = { {STR_NO_FBDEVICE_FILE_ERR, "Cannot open frame buffer device specification file %s (%s)."}, {STR_FBDEV_NAME_ERR, "The %s frame buffer is not supported in %d bit mode."}, {STR_FBDEV_MMAP_ERR, "Cannot mmap() the frame buffer memory (%s)."}, + {STR_VOSF_INIT_ERR, "Cannot initialize Video on SEGV signals."}, {STR_NO_DEV_ZERO_ERR, "Cannot open /dev/zero (%s)."}, {STR_LOW_MEM_MMAP_ERR, "Cannot map Low Memory Globals (%s)."}, {STR_SIGALTSTACK_ERR, "Cannot install alternate signal stack (%s)."}, diff --git a/BasiliskII/src/Unix/user_strings_unix.h b/BasiliskII/src/Unix/user_strings_unix.h index 0f8940a9..a69db4d7 100644 --- a/BasiliskII/src/Unix/user_strings_unix.h +++ b/BasiliskII/src/Unix/user_strings_unix.h @@ -28,6 +28,7 @@ enum { STR_NO_FBDEVICE_FILE_ERR, STR_FBDEV_NAME_ERR, STR_FBDEV_MMAP_ERR, + STR_VOSF_INIT_ERR, STR_NO_DEV_ZERO_ERR, STR_LOW_MEM_MMAP_ERR, STR_SIGALTSTACK_ERR, diff --git a/BasiliskII/src/Unix/video_vosf.h b/BasiliskII/src/Unix/video_vosf.h index 76b705d5..8487c92f 100644 --- a/BasiliskII/src/Unix/video_vosf.h +++ b/BasiliskII/src/Unix/video_vosf.h @@ -24,6 +24,207 @@ // Note: this file is #include'd in video_x.cpp #ifdef ENABLE_VOSF +#include +#include +#include "sigsegv.h" +#include "vm_alloc.h" + +#ifdef ENABLE_MON +# include "mon.h" +#endif + +// Variables for Video on SEGV support +static uint8 *the_host_buffer; // Host frame buffer in VOSF mode +static uint32 the_buffer_size; // Size of allocated the_buffer + +struct ScreenPageInfo { + int top, bottom; // Mapping between this virtual page and Mac scanlines +}; + +struct ScreenInfo { + uintptr memBase; // Real start address + uintptr memStart; // Start address aligned to page boundary + uintptr memEnd; // Address of one-past-the-end of the screen + uint32 memLength; // Length of the memory addressed by the screen pages + + uint32 pageSize; // Size of a page + int pageBits; // Shift count to get the page number + uint32 pageCount; // Number of pages allocated to the screen + + bool dirty; // Flag: set if the frame buffer was touched + char * dirtyPages; // Table of flags set if page was altered + ScreenPageInfo * pageInfo; // Table of mappings page -> Mac scanlines +}; + +static ScreenInfo mainBuffer; + +#define PFLAG_SET_VALUE 0x00 +#define PFLAG_CLEAR_VALUE 0x01 +#define PFLAG_SET_VALUE_4 0x00000000 +#define PFLAG_CLEAR_VALUE_4 0x01010101 +#define PFLAG_SET(page) mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE +#define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE +#define PFLAG_ISSET(page) (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE) +#define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE) + +#ifdef UNALIGNED_PROFITABLE +# define PFLAG_ISSET_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4) +# define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4) +#else +# define PFLAG_ISSET_4(page) \ + PFLAG_ISSET(page ) && PFLAG_ISSET(page+1) \ + && PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3) +# define PFLAG_ISCLEAR_4(page) \ + PFLAG_ISCLEAR(page ) && PFLAG_ISCLEAR(page+1) \ + && PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3) +#endif + +// Set the selected page range [ first_page, last_page [ into the SET state +#define PFLAG_SET_RANGE(first_page, last_page) \ + memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \ + (last_page) - (first_page)) + +// Set the selected page range [ first_page, last_page [ into the CLEAR state +#define PFLAG_CLEAR_RANGE(first_page, last_page) \ + memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \ + (last_page) - (first_page)) + +#define PFLAG_SET_ALL do { \ + PFLAG_SET_RANGE(0, mainBuffer.pageCount); \ + mainBuffer.dirty = true; \ +} while (0) + +#define PFLAG_CLEAR_ALL do { \ + PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \ + mainBuffer.dirty = false; \ +} while (0) + +// Set the following macro definition to 1 if your system +// provides a really fast strchr() implementation +//#define HAVE_FAST_STRCHR 0 + +static inline int find_next_page_set(int page) +{ +#if HAVE_FAST_STRCHR + char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE); + return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; +#else + while (PFLAG_ISCLEAR_4(page)) + page += 4; + while (PFLAG_ISCLEAR(page)) + page++; + return page; +#endif +} + +static inline int find_next_page_clear(int page) +{ +#if HAVE_FAST_STRCHR + char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE); + return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; +#else + while (PFLAG_ISSET_4(page)) + page += 4; + while (PFLAG_ISSET(page)) + page++; + return page; +#endif +} + +static int zero_fd = -1; + +#ifdef HAVE_PTHREADS +static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact) +#define LOCK_VOSF pthread_mutex_lock(&vosf_lock); +#define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock); +#else +#define LOCK_VOSF +#define UNLOCK_VOSF +#endif + +static int log_base_2(uint32 x) +{ + uint32 mask = 0x80000000; + int l = 31; + while (l >= 0 && (x & mask) == 0) { + mask >>= 1; + l--; + } + return l; +} + + +/* + * Initialize mainBuffer structure + */ + +static bool video_init_buffer(void) +{ + if (use_vosf) { + const uint32 page_size = getpagesize(); + const uint32 page_mask = page_size - 1; + + mainBuffer.memBase = (uintptr) the_buffer; + // Align the frame buffer on page boundary + mainBuffer.memStart = (uintptr)((((unsigned long) the_buffer) + page_mask) & ~page_mask); + mainBuffer.memLength = the_buffer_size; + mainBuffer.memEnd = mainBuffer.memStart + mainBuffer.memLength; + + mainBuffer.pageSize = page_size; + mainBuffer.pageCount = (mainBuffer.memLength + page_mask)/mainBuffer.pageSize; + mainBuffer.pageBits = log_base_2(mainBuffer.pageSize); + + if (mainBuffer.dirtyPages) { + free(mainBuffer.dirtyPages); + mainBuffer.dirtyPages = NULL; + } + + mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2); + + if (mainBuffer.pageInfo) { + free(mainBuffer.pageInfo); + mainBuffer.pageInfo = NULL; + } + + mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo)); + + if ((mainBuffer.dirtyPages == 0) || (mainBuffer.pageInfo == 0)) + return false; + + mainBuffer.dirty = false; + + PFLAG_CLEAR_ALL; + // Safety net to insure the loops in the update routines will terminate + // See a discussion in for further details + PFLAG_CLEAR(mainBuffer.pageCount); + PFLAG_SET(mainBuffer.pageCount+1); + + uint32 a = 0; + for (int i = 0; i < mainBuffer.pageCount; i++) { + int y1 = a / VideoMonitor.mode.bytes_per_row; + if (y1 >= VideoMonitor.mode.y) + y1 = VideoMonitor.mode.y - 1; + + int y2 = (a + mainBuffer.pageSize) / VideoMonitor.mode.bytes_per_row; + if (y2 >= VideoMonitor.mode.y) + y2 = VideoMonitor.mode.y - 1; + + mainBuffer.pageInfo[i].top = y1; + mainBuffer.pageInfo[i].bottom = y2; + + a += mainBuffer.pageSize; + if (a > mainBuffer.memLength) + a = mainBuffer.memLength; + } + + // We can now write-protect the frame buffer + if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0) + return false; + } + return true; +} + + /* * Page-aligned memory allocation */ @@ -62,6 +263,16 @@ static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_addres if (fault_instruction != SIGSEGV_INVALID_PC) fprintf(stderr, " [IP=0x%08X]", fault_instruction); fprintf(stderr, "\n"); +#if EMULATED_68K + uaecptr nextpc; + extern void m68k_dumpstate(uaecptr *nextpc); + m68k_dumpstate(&nextpc); +#endif +#ifdef ENABLE_MON + char *arg[4] = {"mon", "-m", "-r", NULL}; + mon(3, arg); + QuitEmulator(); +#endif return false; } @@ -131,7 +342,7 @@ static inline void update_display_window_vosf(void) const int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x; int i = y1 * bytes_per_row, j; - if (depth == 1) { + if (VideoMonitor.mode.depth == VDEPTH_1BIT) { // Update the_host_buffer and copy of the_buffer for (j = y1; j <= y2; j++) { diff --git a/BasiliskII/src/Unix/video_x.cpp b/BasiliskII/src/Unix/video_x.cpp index f89cc949..7a7b895a 100644 --- a/BasiliskII/src/Unix/video_x.cpp +++ b/BasiliskII/src/Unix/video_x.cpp @@ -52,13 +52,6 @@ # include #endif -#ifdef ENABLE_VOSF -# include -# include -# include "sigsegv.h" -# include "vm_alloc.h" -#endif - #include "cpu_emulation.h" #include "main.h" #include "adb.h" @@ -93,7 +86,7 @@ static uint8 *the_buffer; // Mac frame buffer #ifdef HAVE_PTHREADS static bool redraw_thread_active = false; // Flag: Redraw thread installed -static volatile bool redraw_thread_cancel = false; // Flag: Cancel Redraw thread +static volatile bool redraw_thread_cancel; // Flag: Cancel Redraw thread static pthread_t redraw_thread; // Redraw thread #endif @@ -114,11 +107,11 @@ static int keycode_table[256]; // X keycode -> Mac keycode translation tabl // X11 variables static int screen; // Screen number static int xdepth; // Depth of X screen -static int depth; // Depth of Mac frame buffer static Window rootwin, the_win; // Root window and our window static XVisualInfo visualInfo; static Visual *vis; static Colormap cmap[2]; // Two colormaps (DGA) for 8-bit mode +static bool cmap_allocated = false; static XColor black, white; static unsigned long black_pixel, white_pixel; static int eventmask; @@ -178,137 +171,14 @@ static bool use_vosf = true; // Flag: VOSF enabled static const bool use_vosf = false; // Flag: VOSF enabled #endif -#ifdef ENABLE_VOSF -// Variables for Video on SEGV support (taken from the Win32 port) -static uint8 *the_host_buffer; // Host frame buffer in VOSF mode -static uint32 the_buffer_size; // Size of allocated the_buffer - -struct ScreenPageInfo { - int top, bottom; // Mapping between this virtual page and Mac scanlines -}; - -struct ScreenInfo { - uintptr memBase; // Real start address - uintptr memStart; // Start address aligned to page boundary - uintptr memEnd; // Address of one-past-the-end of the screen - uint32 memLength; // Length of the memory addressed by the screen pages - - uint32 pageSize; // Size of a page - int pageBits; // Shift count to get the page number - uint32 pageCount; // Number of pages allocated to the screen - - bool dirty; // Flag: set if the frame buffer was touched - char * dirtyPages; // Table of flags set if page was altered - ScreenPageInfo * pageInfo; // Table of mappings page -> Mac scanlines -}; - -static ScreenInfo mainBuffer; - -#define PFLAG_SET_VALUE 0x00 -#define PFLAG_CLEAR_VALUE 0x01 -#define PFLAG_SET_VALUE_4 0x00000000 -#define PFLAG_CLEAR_VALUE_4 0x01010101 -#define PFLAG_SET(page) mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE -#define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE -#define PFLAG_ISSET(page) (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE) -#define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE) - -#ifdef UNALIGNED_PROFITABLE -# define PFLAG_ISSET_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4) -# define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4) -#else -# define PFLAG_ISSET_4(page) \ - PFLAG_ISSET(page ) && PFLAG_ISSET(page+1) \ - && PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3) -# define PFLAG_ISCLEAR_4(page) \ - PFLAG_ISCLEAR(page ) && PFLAG_ISCLEAR(page+1) \ - && PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3) -#endif - -// Set the selected page range [ first_page, last_page [ into the SET state -#define PFLAG_SET_RANGE(first_page, last_page) \ - memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \ - (last_page) - (first_page)) - -// Set the selected page range [ first_page, last_page [ into the CLEAR state -#define PFLAG_CLEAR_RANGE(first_page, last_page) \ - memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \ - (last_page) - (first_page)) - -#define PFLAG_SET_ALL do { \ - PFLAG_SET_RANGE(0, mainBuffer.pageCount); \ - mainBuffer.dirty = true; \ -} while (0) - -#define PFLAG_CLEAR_ALL do { \ - PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \ - mainBuffer.dirty = false; \ -} while (0) - -// Set the following macro definition to 1 if your system -// provides a really fast strchr() implementation -//#define HAVE_FAST_STRCHR 0 - -static inline int find_next_page_set(int page) -{ -#if HAVE_FAST_STRCHR - char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE); - return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; -#else - while (PFLAG_ISCLEAR_4(page)) - page += 4; - while (PFLAG_ISCLEAR(page)) - page++; - return page; -#endif -} - -static inline int find_next_page_clear(int page) -{ -#if HAVE_FAST_STRCHR - char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE); - return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; -#else - while (PFLAG_ISSET_4(page)) - page += 4; - while (PFLAG_ISSET(page)) - page++; - return page; -#endif -} - -static int zero_fd = -1; - -#ifdef HAVE_PTHREADS -static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact) -#define LOCK_VOSF pthread_mutex_lock(&vosf_lock); -#define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock); -#else -#define LOCK_VOSF -#define UNLOCK_VOSF -#endif - -static int log_base_2(uint32 x) -{ - uint32 mask = 0x80000000; - int l = 31; - while (l >= 0 && (x & mask) == 0) { - mask >>= 1; - l--; - } - return l; -} -#endif /* ENABLE_VOSF */ - // VideoRefresh function -void VideoRefreshInit(void); +static void VideoRefreshInit(void); static void (*video_refresh)(void); // Prototypes static void *redraw_func(void *arg); static int event2keycode(XKeyEvent &ev); - // From main_unix.cpp extern char *x_display_name; extern Display *x_display; @@ -316,6 +186,7 @@ extern Display *x_display; // From sys_unix.cpp extern void SysMountFirstFloppy(void); + #ifdef ENABLE_VOSF # include "video_vosf.h" #endif @@ -325,68 +196,37 @@ extern void SysMountFirstFloppy(void); * Initialization */ -// Add resolution to list of supported modes and set VideoMonitor -static void set_video_monitor(uint32 width, uint32 height, uint32 bytes_per_row, bool native_byte_order) +// Add mode to list of supported modes +static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth) { video_mode mode; + mode.x = width; + mode.y = height; + mode.resolution_id = resolution_id; + mode.bytes_per_row = bytes_per_row; + mode.depth = depth; + VideoModes.push_back(mode); +} + +// Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) +static void set_mac_frame_buffer(video_depth depth, bool native_byte_order) +{ #if !REAL_ADDRESSING && !DIRECT_ADDRESSING int layout = FLAYOUT_DIRECT; - switch (depth) { - case 1: - layout = FLAYOUT_DIRECT; - break; - case 8: - layout = FLAYOUT_DIRECT; - break; - case 15: - layout = FLAYOUT_HOST_555; - break; - case 16: - layout = FLAYOUT_HOST_565; - break; - case 24: - case 32: - layout = FLAYOUT_HOST_888; - break; - } + if (depth == VDEPTH_16BIT) + layout = (xdepth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565; + else if (depth == VDEPTH_32BIT) + layour = (xdepth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT; if (native_byte_order) MacFrameLayout = layout; else MacFrameLayout = FLAYOUT_DIRECT; + VideoMonitor.mac_frame_base = MacFrameBaseMac; +#else + VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); + D(bug("Host frame buffer = %p, ", the_buffer)); #endif - - mode.x = width; - mode.y = height; - mode.resolution_id = 0x80; - mode.bytes_per_row = bytes_per_row; - - switch (depth) { - case 1: - mode.depth = VDEPTH_1BIT; - break; - case 2: - mode.depth = VDEPTH_2BIT; - break; - case 4: - mode.depth = VDEPTH_4BIT; - break; - case 8: - mode.depth = VDEPTH_8BIT; - break; - case 15: - mode.depth = VDEPTH_16BIT; - break; - case 16: - mode.depth = VDEPTH_16BIT; - break; - case 24: - case 32: - mode.depth = VDEPTH_32BIT; - break; - } - - VideoModes.push_back(mode); - VideoMonitor.mode = mode; + D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base)); } // Set window name and class @@ -457,8 +297,9 @@ static int error_handler(Display *d, XErrorEvent *e) } // Init window mode -static bool init_window(int width, int height) +static bool init_window(const video_mode &mode) { + int width = mode.x, height = mode.y; int aligned_width = (width + 15) & ~15; int aligned_height = (height + 15) & ~15; @@ -475,7 +316,7 @@ static bool init_window(int width, int height) wattr.colormap = cmap[0]; the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, - InputOutput, vis, CWEventMask | CWBackPixel | (depth == 8 ? CWColormap : 0), &wattr); + InputOutput, vis, CWEventMask | CWBackPixel | ((IsDirectMode(mode) || mode.depth == VDEPTH_1BIT) ? 0 : CWColormap), &wattr); // Set window name/class set_window_name(the_win, STR_WINDOW_TITLE); @@ -506,10 +347,10 @@ static bool init_window(int width, int height) // Try to create and attach SHM image have_shm = false; - if (depth != 1 && local_X11 && XShmQueryExtension(x_display)) { + if (mode.depth != VDEPTH_1BIT && local_X11 && XShmQueryExtension(x_display)) { // Create SHM image ("height + 2" for safety) - img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height); + img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height); shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777); the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0); shminfo.shmaddr = img->data = (char *)the_buffer_copy; @@ -533,26 +374,13 @@ static bool init_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 = aligned_width; - switch (depth) { - case 1: - bytes_per_row /= 8; - break; - case 15: - case 16: - bytes_per_row *= 2; - break; - case 24: - case 32: - bytes_per_row *= 4; - break; - } + int bytes_per_row = TrivialBytesPerRow(aligned_width, mode.depth); the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row); - img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row); + img = XCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row); } // 1-Bit mode is big-endian - if (depth == 1) { + if (mode.depth == VDEPTH_1BIT) { img->byte_order = MSBFirst; img->bitmap_bit_order = MSBFirst; } @@ -589,20 +417,17 @@ static bool init_window(int width, int height) #ifdef ENABLE_VOSF Screen_blitter_init(&visualInfo, native_byte_order); #endif - set_video_monitor(width, height, img->bytes_per_line, native_byte_order); - -#if REAL_ADDRESSING || DIRECT_ADDRESSING - VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); -#else - VideoMonitor.mac_frame_base = MacFrameBaseMac; -#endif + VideoMonitor.mode = mode; + set_mac_frame_buffer(mode.depth, native_byte_order); return true; } // Init fbdev DGA display -static bool init_fbdev_dga(char *in_fb_name) +static bool init_fbdev_dga(const video_mode &mode) { #ifdef ENABLE_FBDEV_DGA + int width = mode.x, height = mode.y; + // Find the maximum depth available int ndepths, max_depth(0); int *depths = XListDepths(x_display, screen, &ndepths); @@ -645,7 +470,7 @@ static bool init_fbdev_dga(char *in_fb_name) continue; if ((sscanf(line, "%19s %d %x", &fb_name, &fb_depth, &fb_offset) == 3) - && (strcmp(fb_name, in_fb_name) == 0) && (fb_depth == max_depth)) { + && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) { device_found = true; break; } @@ -657,14 +482,12 @@ static bool init_fbdev_dga(char *in_fb_name) // Frame buffer name not found ? Then, display warning if (!device_found) { char str[256]; - sprintf(str, GetString(STR_FBDEV_NAME_ERR), in_fb_name, max_depth); + sprintf(str, GetString(STR_FBDEV_NAME_ERR), fb_name, max_depth); ErrorAlert(str); return false; } - int width = DisplayWidth(x_display, screen); - int height = DisplayHeight(x_display, screen); - depth = fb_depth; // max_depth + depth = fb_depth; // Set relative mouse mode ADBSetRelMouseMode(false); @@ -699,22 +522,10 @@ static bool init_fbdev_dga(char *in_fb_name) PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, the_win, None, CurrentTime); - // Set VideoMonitor - int bytes_per_row = width; - switch (depth) { - case 1: - bytes_per_row = ((width | 7) & ~7) >> 3; - break; - case 15: - case 16: - bytes_per_row *= 2; - break; - case 24: - case 32: - bytes_per_row *= 4; - break; - } + // Calculate bytes per row + int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth); + // Map frame buffer if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) { if ((the_buffer = (uint8 *) mmap(NULL, height * bytes_per_row, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) { char str[256]; @@ -742,12 +553,9 @@ static bool init_fbdev_dga(char *in_fb_name) #endif #endif - set_video_monitor(width, height, bytes_per_row, true); -#if REAL_ADDRESSING || DIRECT_ADDRESSING - VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); -#else - VideoMonitor.mac_frame_base = MacFrameBaseMac; -#endif + // Set VideoMonitor + VideoMonitor.mode = mode; + set_mac_frame_buffer(mode.depth, true); return true; #else ErrorAlert("Basilisk II has been compiled with fbdev DGA support disabled."); @@ -756,8 +564,10 @@ static bool init_fbdev_dga(char *in_fb_name) } // Init XF86 DGA display -static bool init_xf86_dga(int width, int height) +static bool init_xf86_dga(const video_mode &mode) { + int width = mode.x, height = mode.y; + #ifdef ENABLE_XF86_DGA // Set relative mouse mode ADBSetRelMouseMode(true); @@ -809,27 +619,14 @@ static bool init_xf86_dga(int width, int height) XF86DGASetVidPage(x_display, screen, 0); // Set colormap - if (depth == 8) { + if (!IsDirectMode(mode)) { XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]); XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } XSync(x_display, false); // Set VideoMonitor - int bytes_per_row = (v_width + 7) & ~7; - switch (depth) { - case 1: - bytes_per_row /= 8; - break; - case 15: - case 16: - bytes_per_row *= 2; - break; - case 24: - case 32: - bytes_per_row *= 4; - break; - } + int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth); #ifdef VIDEO_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING @@ -849,13 +646,9 @@ static bool init_xf86_dga(int width, int height) #endif #endif - set_video_monitor(width, height, bytes_per_row, true); -#if REAL_ADDRESSING || DIRECT_ADDRESSING - VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); -// MacFrameLayout = FLAYOUT_DIRECT; -#else - VideoMonitor.mac_frame_base = MacFrameBaseMac; -#endif + const_cast(&mode)->bytes_per_row = bytes_per_row; + VideoMonitor.mode = mode; + set_mac_frame_buffer(mode.depth, true); return true; #else ErrorAlert("Basilisk II has been compiled with XF86 DGA support disabled."); @@ -928,72 +721,87 @@ static void keycode_init(void) } } -bool VideoInitBuffer() +// Open display for specified mode +static bool video_open(const video_mode &mode) { + // Create color maps for 8 bit mode + if (!IsDirectMode(mode)) { + cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); + cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); + cmap_allocated = true; + XInstallColormap(x_display, cmap[0]); + XInstallColormap(x_display, cmap[1]); + } + + // Initialize according to display type + switch (display_type) { + case DISPLAY_WINDOW: + if (!init_window(mode)) + return false; + break; + case DISPLAY_DGA: +#ifdef ENABLE_FBDEV_DGA + if (!init_fbdev_dga(mode)) +#else + if (!init_xf86_dga(mode)) +#endif + return false; + break; + } + + // Lock down frame buffer + LOCK_FRAME_BUFFER; + +#if !REAL_ADDRESSING && !DIRECT_ADDRESSING + // Set variables for UAE memory mapping + MacFrameBaseHost = the_buffer; + MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; + + // No special frame buffer in Classic mode (frame buffer is in Mac RAM) + if (classic) + MacFrameLayout = FLAYOUT_NONE; +#endif + + InitFrameBufferMapping(); + #ifdef ENABLE_VOSF if (use_vosf) { - const uint32 page_size = getpagesize(); - const uint32 page_mask = page_size - 1; - - mainBuffer.memBase = (uintptr) the_buffer; - // Align the frame buffer on page boundary - mainBuffer.memStart = (uintptr)((((unsigned long) the_buffer) + page_mask) & ~page_mask); - mainBuffer.memLength = the_buffer_size; - mainBuffer.memEnd = mainBuffer.memStart + mainBuffer.memLength; - - mainBuffer.pageSize = page_size; - mainBuffer.pageCount = (mainBuffer.memLength + page_mask)/mainBuffer.pageSize; - mainBuffer.pageBits = log_base_2(mainBuffer.pageSize); - - if (mainBuffer.dirtyPages != 0) - free(mainBuffer.dirtyPages); - - mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2); - - if (mainBuffer.pageInfo != 0) - free(mainBuffer.pageInfo); - - mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo)); - - if ((mainBuffer.dirtyPages == 0) || (mainBuffer.pageInfo == 0)) - return false; - - mainBuffer.dirty = false; - - PFLAG_CLEAR_ALL; - // Safety net to insure the loops in the update routines will terminate - // See a discussion in for further details - PFLAG_CLEAR(mainBuffer.pageCount); - PFLAG_SET(mainBuffer.pageCount+1); - - uint32 a = 0; - for (int i = 0; i < mainBuffer.pageCount; i++) { - int y1 = a / VideoMonitor.mode.bytes_per_row; - if (y1 >= VideoMonitor.mode.y) - y1 = VideoMonitor.mode.y - 1; - - int y2 = (a + mainBuffer.pageSize) / VideoMonitor.mode.bytes_per_row; - if (y2 >= VideoMonitor.mode.y) - y2 = VideoMonitor.mode.y - 1; - - mainBuffer.pageInfo[i].top = y1; - mainBuffer.pageInfo[i].bottom = y2; - - a += mainBuffer.pageSize; - if (a > mainBuffer.memLength) - a = mainBuffer.memLength; + // Initialize the mainBuffer structure + if (!video_init_buffer()) { + ErrorAlert(GetString(STR_VOSF_INIT_ERR)); + return false; } - - // We can now write-protect the frame buffer - if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0) + + // Initialize the handler for SIGSEGV + if (!sigsegv_install_handler(screen_fault_handler)) { + ErrorAlert("Could not initialize Video on SEGV signals"); return false; + } } #endif + + // Initialize VideoRefresh function + VideoRefreshInit(); + + XSync(x_display, false); + +#ifdef HAVE_PTHREADS + // Start redraw/input thread + redraw_thread_cancel = false; + redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0); + if (!redraw_thread_active) { + printf("FATAL: cannot create redraw thread\n"); + return false; + } +#endif + return true; } bool VideoInit(bool classic) { + classic_mode = classic; + #ifdef ENABLE_VOSF // Open /dev/zero zero_fd = open("/dev/zero", O_RDWR); @@ -1094,112 +902,69 @@ bool VideoInit(bool classic) } vis = visualInfo.visual; - // Mac screen depth is always 1 bit in Classic mode, but follows X depth otherwise - classic_mode = classic; - if (classic) - depth = 1; - else - depth = xdepth; - - // Create color maps for 8 bit mode - if (depth == 8) { - cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); - cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); - XInstallColormap(x_display, cmap[0]); - XInstallColormap(x_display, cmap[1]); - } - // Get screen mode from preferences const char *mode_str; - if (classic) + if (classic_mode) mode_str = "win/512/342"; else mode_str = PrefsFindString("screen"); - // Determine type and mode - int width = 512, height = 384; + // Determine display type and default dimensions + int default_width = 512, default_height = 384; display_type = DISPLAY_WINDOW; if (mode_str) { - if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2) + if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2) { display_type = DISPLAY_WINDOW; #ifdef ENABLE_FBDEV_DGA - else if (has_dga && sscanf(mode_str, "dga/%19s", fb_name) == 1) { -#else - else if (has_dga && sscanf(mode_str, "dga/%d/%d", &width, &height) == 2) { -#endif + } else if (has_dga && sscanf(mode_str, "dga/%19s", fb_name) == 1) { display_type = DISPLAY_DGA; - if (width > DisplayWidth(x_display, screen)) - width = DisplayWidth(x_display, screen); - if (height > DisplayHeight(x_display, screen)) - height = DisplayHeight(x_display, screen); - } - if (width <= 0) - width = DisplayWidth(x_display, screen); - if (height <= 0) - height = DisplayHeight(x_display, screen); - } - - // Initialize according to display type - switch (display_type) { - case DISPLAY_WINDOW: - if (!init_window(width, height)) - return false; - break; - case DISPLAY_DGA: -#ifdef ENABLE_FBDEV_DGA - if (!init_fbdev_dga(fb_name)) + default_width = -1; default_height = -1; #else - if (!init_xf86_dga(width, height)) + } else if (has_dga && sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) { + display_type = DISPLAY_DGA; #endif - return false; - break; - } - - // Lock down frame buffer - LOCK_FRAME_BUFFER; - -#if !REAL_ADDRESSING && !DIRECT_ADDRESSING - // Set variables for UAE memory mapping - MacFrameBaseHost = the_buffer; - MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; - - // No special frame buffer in Classic mode (frame buffer is in Mac RAM) - if (classic) - MacFrameLayout = FLAYOUT_NONE; -#endif - -#ifdef ENABLE_VOSF - if (use_vosf) { - // Initialize the mainBuffer structure - if (!VideoInitBuffer()) { - // TODO: STR_VOSF_INIT_ERR ? - ErrorAlert("Could not initialize Video on SEGV signals"); - return false; - } - - // Initialize the handler for SIGSEGV - if (!sigsegv_install_handler(screen_fault_handler)) { - // TODO: STR_VOSF_INIT_ERR ? - ErrorAlert("Could not initialize Video on SEGV signals"); - return false; } } -#endif - - // Initialize VideoRefresh function - VideoRefreshInit(); - - XSync(x_display, false); + if (default_width <= 0) + default_width = DisplayWidth(x_display, screen); + else if (default_width > DisplayWidth(x_display, screen)) + default_width = DisplayWidth(x_display, screen); + if (default_height <= 0) + default_height = DisplayHeight(x_display, screen); + else if (default_height > DisplayHeight(x_display, screen)) + default_height = DisplayHeight(x_display, screen); -#ifdef HAVE_PTHREADS - // Start redraw/input thread - redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0); - if (!redraw_thread_active) { - printf("FATAL: cannot create redraw thread\n"); - return false; + // Mac screen depth is always 1 bit in Classic mode, but follows X depth otherwise + int depth = (classic_mode ? 1 : xdepth); + video_depth depth_mode = DepthModeForPixelDepth(depth); + + // Construct list of supported modes + if (display_type == DISPLAY_WINDOW) { + if (classic) + add_mode(512, 342, 0x80, 64, depth_mode); + else { + add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth_mode), depth_mode); + add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth_mode), depth_mode); + add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth_mode), depth_mode); + add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth_mode), depth_mode); + add_mode(1280, 1024, 0x84, TrivialBytesPerRow(1280, depth_mode), depth_mode); + } + } else + add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, depth_mode), depth_mode); + + // Find requested default mode and open display + if (VideoModes.size() == 1) + return video_open(VideoModes[0]); + else { + // Find mode with specified dimensions + std::vector::const_iterator i = VideoModes.begin(), end = VideoModes.end(); + while (i != end) { + if (i->x == default_width && i->y == default_height) + return video_open(*i); + ++i; + } + return video_open(VideoModes[0]); } -#endif - return true; } @@ -1207,7 +972,8 @@ bool VideoInit(bool classic) * Deinitialization */ -void VideoExit(void) +// Close display +static void video_close(void) { #ifdef HAVE_PTHREADS // Stop redraw thread @@ -1251,9 +1017,23 @@ void VideoExit(void) XFlush(x_display); XSync(x_display, false); - if (depth == 8) { + XUnmapWindow(x_display, the_win); + wait_unmapped(the_win); + XDestroyWindow(x_display, the_win); + + if (have_shm) { + XDestroyImage(img); + XShmDetach(x_display, &shminfo); + have_shm = false; + } else { + //!! free img + } + //!! free the_gc + + if (cmap_allocated) { XFreeColormap(x_display, cmap[0]); XFreeColormap(x_display, cmap[1]); + cmap_allocated = false; } if (!use_vosf) { @@ -1269,6 +1049,8 @@ void VideoExit(void) } #ifdef ENABLE_VOSF else { + //!! uninstall SEGV handler? + if (the_buffer != (uint8 *)VM_MAP_FAILED) { vm_release(the_buffer, the_buffer_size); the_buffer = 0; @@ -1295,7 +1077,14 @@ void VideoExit(void) mainBuffer.dirtyPages = 0; } } +#endif +} +void VideoExit(void) +{ + video_close(); + +#ifdef ENABLE_VOSF // Close /dev/zero if (zero_fd > 0) close(zero_fd); @@ -1362,6 +1151,8 @@ void video_set_palette(uint8 *pal) void video_switch_to_mode(const video_mode &mode) { + video_close(); + video_open(mode); } @@ -1450,7 +1241,7 @@ static void resume_emul(void) } #ifdef ENABLE_XF86_DGA - if (depth == 8) + if (!IsDirectMode(VideoMonitor.mode)) XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); #endif @@ -1819,7 +1610,7 @@ static void update_display_dynamic(int ticker) i = (yi * bytes_per_row) + xi; for (y2=0; y2 < yil; y2++, i += bytes_per_row) memcpy(&the_buffer_copy[i], &the_buffer[i], xil); - if (depth == 1) { + if (VideoMonitor.mode.depth == VDEPTH_1BIT) { if (have_shm) XShmPutImage(x_display, the_win, the_gc, img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0); else @@ -1874,7 +1665,7 @@ static void update_display_static(void) // Check for first column from left and first column from right that have changed if (high) { - if (depth == 1) { + if (VideoMonitor.mode.depth == VDEPTH_1BIT) { x1 = VideoMonitor.mode.x - 1; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; @@ -1983,18 +1774,18 @@ static inline void possibly_quit_dga_mode() XUngrabPointer(x_display, CurrentTime); XUngrabKeyboard(x_display, CurrentTime); XUnmapWindow(x_display, the_win); - XSync(x_display, false); + wait_unmapped(the_win); } #endif } -static inline void handle_palette_changes(int depth, int display_type) +static inline void handle_palette_changes(int display_type) { LOCK_PALETTE; if (palette_changed) { palette_changed = false; - if (depth == 8) { + if (!IsDirectMode(VideoMonitor.mode)) { XStoreColors(x_display, cmap[0], palette, 256); XStoreColors(x_display, cmap[1], palette, 256); XSync(x_display, false); @@ -2020,7 +1811,7 @@ static void video_refresh_dga(void) handle_events(); // Handle palette changes - handle_palette_changes(depth, DISPLAY_DGA); + handle_palette_changes(DISPLAY_DGA); } #ifdef ENABLE_VOSF @@ -2034,7 +1825,7 @@ static void video_refresh_dga_vosf(void) handle_events(); // Handle palette changes - handle_palette_changes(depth, DISPLAY_DGA); + handle_palette_changes(DISPLAY_DGA); // Update display (VOSF variant) static int tick_counter = 0; @@ -2058,7 +1849,7 @@ static void video_refresh_window_vosf(void) handle_events(); // Handle palette changes - handle_palette_changes(depth, DISPLAY_WINDOW); + handle_palette_changes(DISPLAY_WINDOW); // Update display (VOSF variant) static int tick_counter = 0; @@ -2080,7 +1871,7 @@ static void video_refresh_window_static(void) handle_events(); // Handle_palette changes - handle_palette_changes(depth, DISPLAY_WINDOW); + handle_palette_changes(DISPLAY_WINDOW); // Update display (static variant) static int tick_counter = 0; @@ -2096,7 +1887,7 @@ static void video_refresh_window_dynamic(void) handle_events(); // Handle_palette changes - handle_palette_changes(depth, DISPLAY_WINDOW); + handle_palette_changes(DISPLAY_WINDOW); // Update display (dynamic variant) static int tick_counter = 0; @@ -2109,7 +1900,7 @@ static void video_refresh_window_dynamic(void) * Thread for screen refresh, input handling etc. */ -void VideoRefreshInit(void) +static void VideoRefreshInit(void) { // TODO: set up specialised 8bpp VideoRefresh handlers ? if (display_type == DISPLAY_DGA) { diff --git a/BasiliskII/src/include/video.h b/BasiliskII/src/include/video.h index 40c80542..0ad697dc 100644 --- a/BasiliskII/src/include/video.h +++ b/BasiliskII/src/include/video.h @@ -33,11 +33,6 @@ enum video_depth { VDEPTH_32BIT // "Millions" }; -inline bool IsDirectMode(video_depth depth) -{ - return depth == VDEPTH_16BIT || depth == VDEPTH_32BIT; -} - inline uint16 DepthToAppleMode(video_depth depth) { return depth + 0x80; @@ -48,6 +43,42 @@ inline video_depth AppleModeToDepth(uint16 mode) return video_depth(mode - 0x80); } +inline bool IsDirectMode(video_depth depth) +{ + return depth == VDEPTH_16BIT || depth == VDEPTH_32BIT; +} + +inline bool IsDirectMode(uint16 mode) +{ + return IsDirectMode(AppleModeToDepth(mode)); +} + +inline video_depth DepthModeForPixelDepth(int depth) +{ + switch (depth) { + case 1: return VDEPTH_1BIT; + case 2: return VDEPTH_2BIT; + case 4: return VDEPTH_4BIT; + case 8: return VDEPTH_8BIT; + case 15: case 16: return VDEPTH_16BIT; + case 24: case 32: return VDEPTH_32BIT; + default: return VDEPTH_1BIT; + } +} + +// Return a bytes-per-row value that assumes no padding for specified depth and pixel width +inline uint32 TrivialBytesPerRow(uint32 width, video_depth depth) +{ + switch (depth) { + case VDEPTH_1BIT: return width / 8; + case VDEPTH_2BIT: return width / 4; + case VDEPTH_4BIT: return width / 2; + case VDEPTH_8BIT: return width; + case VDEPTH_16BIT: return width * 2; + case VDEPTH_32BIT: return width * 4; + } +} + // Description of one video mode struct video_mode { uint32 x; // X size of screen (pixels) @@ -63,7 +94,7 @@ inline bool IsDirectMode(const video_mode &mode) } // List of all supported video modes -extern vector VideoModes; +extern std::vector VideoModes; // Description for one (possibly virtual) monitor struct monitor_desc { diff --git a/BasiliskII/src/include/video_defs.h b/BasiliskII/src/include/video_defs.h index 521a8f3e..4c4e0c41 100644 --- a/BasiliskII/src/include/video_defs.h +++ b/BasiliskII/src/include/video_defs.h @@ -23,8 +23,6 @@ // Video driver control codes enum { - cscReset = 0, - cscKillIO = 1, cscSetMode = 2, cscSetEntries = 3, cscSetGamma = 4, @@ -42,21 +40,20 @@ enum { cscSetPowerState = 25, cscPrivateControlCall = 26, cscSetMultiConnect = 27, - cscSetClutBehavior = 28, - cscUnusedCall = 127 + cscSetClutBehavior = 28 }; // Video driver status codes enum { cscGetMode = 2, cscGetEntries = 3, - cscGetPageCnt = 4, - cscGetPageBase = 5, + cscGetPages = 4, + cscGetBaseAddress = 5, cscGetGray = 6, cscGetInterrupt = 7, cscGetGamma = 8, cscGetDefaultMode = 9, - cscGetCurMode = 10, + cscGetCurrentMode = 10, cscGetSync = 11, cscGetConnection = 12, cscGetModeTiming = 13, @@ -142,4 +139,31 @@ enum { // VPBlock struct vpPlaneBytes = 38 }; +enum { // SPBlock struct + spResult = 0, + spPointer = 4, + spSize = 8, + spOffsetData = 12, + spIOFileName = 16, + spExecPBlk = 20, + spParamData = 24, + spMisc = 28, + spReserved = 32, + spIOReserved = 36, + spRefNum = 38, + spCategory = 40, + spCType = 42, + spDrvrSW = 44, + spDrvrHW = 46, + spTBMask = 48, + spSlot = 49, + spID = 50, + spExtDev = 51, + spHwDev = 52, + spByteLanes = 53, + spFlags = 54, + spKey = 55, + SIZEOF_SPBlock = 56 +}; + #endif diff --git a/BasiliskII/src/slot_rom.cpp b/BasiliskII/src/slot_rom.cpp index d003a934..7d1e6ab4 100644 --- a/BasiliskII/src/slot_rom.cpp +++ b/BasiliskII/src/slot_rom.cpp @@ -118,58 +118,58 @@ static void PString(char *str) static uint32 VModeParms(uint32 width, uint32 height, uint32 bytes_per_row, video_depth depth) { uint32 ret = p; - Long(50); // Length - Long(0); // Base offset - Word(bytes_per_row); // Row bytes - Word(0); // Bounds + Long(50); // Length + Long(0); // Base offset + Word(bytes_per_row); // Row bytes + Word(0); // Bounds Word(0); Word(height); Word(width); - Word(0); // Version - Word(0); // Pack type - Long(0); // Pack size - Long(0x00480000); // HRes - Long(0x00480000); // VRes + Word(0); // Version + Word(0); // Pack type + Long(0); // Pack size + Long(0x00480000); // HRes + Long(0x00480000); // VRes switch (depth) { case VDEPTH_1BIT: - Word(0); // Pixel type (indirect) - Word(1); // Pixel size - Word(1); // CmpCount - Word(1); // CmpSize + Word(0); // Pixel type (indirect) + Word(1); // Pixel size + Word(1); // CmpCount + Word(1); // CmpSize break; case VDEPTH_2BIT: - Word(0); // Pixel type (indirect) - Word(2); // Pixel size - Word(1); // CmpCount - Word(2); // CmpSize + Word(0); // Pixel type (indirect) + Word(2); // Pixel size + Word(1); // CmpCount + Word(2); // CmpSize break; case VDEPTH_4BIT: - Word(0); // Pixel type (indirect) - Word(4); // Pixel size - Word(1); // CmpCount - Word(4); // CmpSize + Word(0); // Pixel type (indirect) + Word(4); // Pixel size + Word(1); // CmpCount + Word(4); // CmpSize break; case VDEPTH_8BIT: - Word(0); // Pixel type (indirect) - Word(8); // Pixel size - Word(1); // CmpCount - Word(8); // CmpSize + Word(0); // Pixel type (indirect) + Word(8); // Pixel size + Word(1); // CmpCount + Word(8); // CmpSize break; case VDEPTH_16BIT: - Word(16); // Pixel type (direct) - Word(16); // Pixel size - Word(3); // CmpCount - Word(5); // CmpSize + Word(16); // Pixel type (direct) + Word(16); // Pixel size + Word(3); // CmpCount + Word(5); // CmpSize break; case VDEPTH_32BIT: - Word(16); // Pixel type (direct) - Word(32); // Pixel size - Word(3); // CmpCount - Word(8); // CmpSize + Word(16); // Pixel type (direct) + Word(32); // Pixel size + Word(3); // CmpCount + Word(8); // CmpSize break; } - Long(0); // Plane size - Long(0); // Reserved + Long(0); // Plane size + Long(0); // Reserved return ret; } @@ -233,13 +233,13 @@ bool InstallSlotROM(void) // Video sResource for default mode videoType = p; // Literals - Word(3); Word(1); Word(1); Word(0x4232); // Display Video Apple 'B2' + Word(3); Word(1); Word(1); Word(0x4232); // Display Video Apple 'B2' videoName = p; String("Display_Video_Apple_Basilisk"); minorBase = p; - Long(VideoMonitor.mac_frame_base); // Frame buffer base + Long(VideoMonitor.mac_frame_base); // Frame buffer base minorLength = p; - Long(VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); // Frame buffer size + Long(0); // Frame buffer size (unspecified) videoDrvr = p; // Video driver Long(0x72); // Length diff --git a/BasiliskII/src/uae_cpu/basilisk_glue.cpp b/BasiliskII/src/uae_cpu/basilisk_glue.cpp index b3f3ea3b..18e34725 100644 --- a/BasiliskII/src/uae_cpu/basilisk_glue.cpp +++ b/BasiliskII/src/uae_cpu/basilisk_glue.cpp @@ -104,6 +104,17 @@ void Exit680x0(void) } +/* + * Initialize memory mapping of frame buffer (called upon video mode change) + */ + +void InitFrameBufferMapping(void) +{ +#if !REAL_ADDRESSING && !DIRECT_ADDRESSING + memory_init(); +#endif +} + /* * Reset and start 680x0 emulation (doesn't return) */ diff --git a/BasiliskII/src/uae_cpu/cpu_emulation.h b/BasiliskII/src/uae_cpu/cpu_emulation.h index 01702220..32543f4c 100644 --- a/BasiliskII/src/uae_cpu/cpu_emulation.h +++ b/BasiliskII/src/uae_cpu/cpu_emulation.h @@ -37,10 +37,10 @@ extern uint32 ROMBaseMac; // ROM base (Mac address space) extern uint8 *ROMBaseHost; // ROM base (host address space) extern uint32 ROMSize; // Size of ROM -#if !REAL_ADDRESSING -// If we are not using real addressing, the Mac frame buffer gets mapped to this location -// The memory must be allocated by VideoInit(). If multiple monitors are used, they must -// share the frame buffer +#if !REAL_ADDRESSING && !DIRECT_ADDRESSING +// If we are not using real or direct addressing, the Mac frame buffer gets +// mapped to this location. The memory must be allocated by VideoInit(). +// If multiple monitors are used, they must share the frame buffer const uint32 MacFrameBaseMac = 0xa0000000; extern uint8 *MacFrameBaseHost; // Frame buffer base (host address space) extern uint32 MacFrameSize; // Size of frame buffer @@ -80,6 +80,7 @@ static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return me // Initialization extern bool Init680x0(void); // This routine may want to look at CPUType/FPUType to set up the apropriate emulation extern void Exit680x0(void); +extern void InitFrameBufferMapping(void); // 680x0 emulation functions struct M68kRegisters; diff --git a/BasiliskII/src/uae_cpu/cpuopti.c b/BasiliskII/src/uae_cpu/cpuopti.c index 2dc10507..297c5216 100644 --- a/BasiliskII/src/uae_cpu/cpuopti.c +++ b/BasiliskII/src/uae_cpu/cpuopti.c @@ -27,7 +27,7 @@ struct func { static void oops(void) { fprintf(stderr, "Don't know how to optimize this file.\n"); - abort(); + exit(1); } static char * match(struct line *l, const char *m) @@ -46,7 +46,7 @@ static int insn_references_reg (struct line *l, char *reg) { if (reg[0] != 'e') { fprintf(stderr, "Unknown register?!?\n"); - abort(); + exit(1); } if (strstr (l->data, reg) != 0) return 1; @@ -121,7 +121,7 @@ static void do_function(struct func *f) l3 = l3->prev; } if (l3 == l2) - abort(); + exit(1); for (l4 = l2; l4 != l3; l4 = l4->prev) { /* The register may not be referenced by any of the insns that we * move the popl past */ diff --git a/BasiliskII/src/uae_cpu/memory.cpp b/BasiliskII/src/uae_cpu/memory.cpp index 1c7a3a58..05c10504 100644 --- a/BasiliskII/src/uae_cpu/memory.cpp +++ b/BasiliskII/src/uae_cpu/memory.cpp @@ -556,21 +556,18 @@ addrbank frame_host_888_bank = { frame_xlate, frame_check }; +void InitFrameBufferMapping(void) +{ + +} + void memory_init(void) { - char buffer[4096]; - char *nam; - int i, fd; - - for(i=0; i<65536; i++) + for(long i=0; i<65536; i++) put_mem_bank(i<<16, &dummy_bank); // Limit RAM size to not overlap ROM -#if REAL_ADDRESSING - uint32 ram_size = RAMSize; -#else uint32 ram_size = RAMSize > ROMBaseMac ? ROMBaseMac : RAMSize; -#endif RAMBaseDiff = (uae_u32)RAMBaseHost - (uae_u32)RAMBaseMac; ROMBaseDiff = (uae_u32)ROMBaseHost - (uae_u32)ROMBaseMac; diff --git a/BasiliskII/src/video.cpp b/BasiliskII/src/video.cpp index a3a7ef7a..82e3a1c0 100644 --- a/BasiliskII/src/video.cpp +++ b/BasiliskII/src/video.cpp @@ -34,7 +34,7 @@ #include "video.h" #include "video_defs.h" -#define DEBUG 1 +#define DEBUG 0 #include "debug.h" @@ -50,10 +50,12 @@ struct { uint8 palette[256 * 3]; // Color palette, 256 entries, RGB bool luminance_mapping; // Luminance mapping on/off bool interrupts_enabled; // VBL interrupts on/off + uint32 gamma_table; // Mac address of gamma table uint16 current_mode; // Currently selected depth/resolution uint32 current_id; uint16 preferred_mode; // Preferred depth/resolution uint32 preferred_id; + uint32 sp; // Mac address of Slot Manager parameter block } VidLocal; @@ -124,6 +126,23 @@ static void get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) } +/* + * Set palette to 50% gray + */ + +static void set_gray_palette(void) +{ + if (!IsDirectMode(VidLocal.current_mode)) { + for (int i=0; i<256; i++) { + VidLocal.palette[i * 3 + 0] = 127; + VidLocal.palette[i * 3 + 1] = 127; + VidLocal.palette[i * 3 + 2] = 127; + } + video_set_palette(VidLocal.palette); + } +} + + /* * Driver Open() routine */ @@ -145,15 +164,20 @@ int16 VideoDriverOpen(uint32 pb, uint32 dce) VidLocal.preferred_mode = VidLocal.current_mode; VidLocal.preferred_id = VidLocal.current_id; + // Allocate Slot Manager parameter block in Mac RAM + M68kRegisters r; + r.d[0] = SIZEOF_SPBlock; + Execute68kTrap(0xa71e, &r); // NewPtrSysClear() + if (r.a[0] == 0) + return memFullErr; + VidLocal.sp = r.a[0]; + D(bug("SPBlock at %08x\n", VidLocal.sp)); + + // Find and set default gamma table + VidLocal.gamma_table = 0; //!! + // Init color palette (solid gray) - if (!IsDirectMode(VidLocal.desc->mode)) { - for (int i=0; i<256; i++) { - VidLocal.palette[i * 3 + 0] = 127; - VidLocal.palette[i * 3 + 1] = 127; - VidLocal.palette[i * 3 + 2] = 127; - } - video_set_palette(VidLocal.palette); - } + set_gray_palette(); return noErr; } @@ -173,51 +197,63 @@ int16 VideoDriverControl(uint32 pb, uint32 dce) uint16 mode = ReadMacInt16(param + csMode); D(bug(" SetMode %04x\n", mode)); + // Set old base address in case the switch fails + WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + + if (ReadMacInt16(param + csPage)) + return paramErr; + if (mode != VidLocal.current_mode) { std::vector::const_iterator i = find_mode(mode, VidLocal.current_id); - if (i == VideoModes.end()) { - WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + if (i == VideoModes.end()) return paramErr; - } + set_gray_palette(); video_switch_to_mode(*i); VidLocal.current_mode = mode; + WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + WriteMacInt32(dce + dCtlDevBase, VidLocal.desc->mac_frame_base); } - WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + D(bug(" base %08x\n", VidLocal.desc->mac_frame_base)); return noErr; } case cscSetEntries: { // Set palette - D(bug(" SetEntries table %08lx, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); - if (IsDirectMode(VidLocal.desc->mode)) + D(bug(" SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); + if (IsDirectMode(VidLocal.current_mode)) return controlErr; uint32 s_pal = ReadMacInt32(param + csTable); // Source palette uint8 *d_pal; // Destination palette + uint16 start = ReadMacInt16(param + csStart); uint16 count = ReadMacInt16(param + csCount); - if (!s_pal || count > 255) + if (s_pal == 0 || count > 255) return paramErr; - if (ReadMacInt16(param + csStart) == 0xffff) { // Indexed + if (start == 0xffff) { // Indexed for (uint32 i=0; i<=count; i++) { - d_pal = VidLocal.palette + ReadMacInt16(s_pal) * 3; + d_pal = VidLocal.palette + (ReadMacInt16(s_pal) & 0xff) * 3; uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; if (VidLocal.luminance_mapping) red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; + //!! gamma correction *d_pal++ = red; *d_pal++ = green; *d_pal++ = blue; s_pal += 8; } - } else { // Sequential - d_pal = VidLocal.palette + ReadMacInt16(param + csStart) * 3; + } else { // Sequential + if (start + count > 255) + return paramErr; + d_pal = VidLocal.palette + start * 3; for (uint32 i=0; i<=count; i++) { uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; if (VidLocal.luminance_mapping) red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; + //!! gamma correction *d_pal++ = red; *d_pal++ = green; *d_pal++ = blue; @@ -231,7 +267,7 @@ int16 VideoDriverControl(uint32 pb, uint32 dce) case cscSetGamma: // Set gamma table D(bug(" SetGamma\n")); //!! - return noErr; + return controlErr; case cscGrayPage: { // Fill page with dithered gray pattern D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage))); @@ -248,15 +284,17 @@ int16 VideoDriverControl(uint32 pb, uint32 dce) }; uint32 p = VidLocal.desc->mac_frame_base; uint32 pat = pattern[VidLocal.desc->mode.depth]; + bool invert = (VidLocal.desc->mode.depth == VDEPTH_32BIT); for (uint32 y=0; ymode.y; y++) { for (uint32 x=0; xmode.bytes_per_row; x+=4) { WriteMacInt32(p + x, pat); - if (VidLocal.desc->mode.depth == VDEPTH_32BIT) + if (invert) pat = ~pat; } p += VidLocal.desc->mode.bytes_per_row; pat = ~pat; } + //!! if direct mode, load gamma table to CLUT return noErr; } @@ -270,8 +308,6 @@ int16 VideoDriverControl(uint32 pb, uint32 dce) VidLocal.interrupts_enabled = (ReadMacInt8(param + csMode) == 0); return noErr; - // case cscDirectSetEntries: - case cscSetDefaultMode: { // Set default color depth uint16 mode = ReadMacInt16(param + csMode); D(bug(" SetDefaultMode %04x\n", mode)); @@ -284,17 +320,70 @@ int16 VideoDriverControl(uint32 pb, uint32 dce) uint32 id = ReadMacInt32(param + csData); D(bug(" SwitchMode %04x, %08x\n", mode, id)); + // Set old base address in case the switch fails + WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + + if (ReadMacInt16(param + csPage)) + return paramErr; + if (mode != VidLocal.current_mode || id != VidLocal.current_id) { std::vector::const_iterator i = find_mode(mode, id); - if (i == VideoModes.end()) { - WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + if (i == VideoModes.end()) return paramErr; - } + set_gray_palette(); video_switch_to_mode(*i); VidLocal.current_mode = mode; VidLocal.current_id = id; + uint32 frame_base = VidLocal.desc->mac_frame_base; + WriteMacInt32(param + csBaseAddr, frame_base); + + M68kRegisters r; + uint32 sp = VidLocal.sp; + r.a[0] = sp; + + // Find functional sResource for this display + WriteMacInt8(sp + spSlot, ReadMacInt8(dce + dCtlSlot)); + WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId)); + WriteMacInt8(sp + spExtDev, 0); + r.d[0] = 0x0016; + Execute68kTrap(0xa06e, &r); // SRsrcInfo() + uint32 rsrc = ReadMacInt32(sp + spPointer); + + // Patch minorBase + WriteMacInt8(sp + spID, 0x0a); // minorBase + r.d[0] = 0x0006; + Execute68kTrap(0xa06e, &r); // SFindStruct() + uint32 minor_base = ReadMacInt32(sp + spPointer) - ROMBaseMac; + ROMBaseHost[minor_base + 0] = frame_base >> 24; + ROMBaseHost[minor_base + 1] = frame_base >> 16; + ROMBaseHost[minor_base + 2] = frame_base >> 8; + ROMBaseHost[minor_base + 3] = frame_base; + + // Patch video mode parameter table + WriteMacInt32(sp + spPointer, rsrc); + WriteMacInt8(sp + spID, mode); + r.d[0] = 0x0006; + Execute68kTrap(0xa06e, &r); // SFindStruct() + WriteMacInt8(sp + spID, 0x01); + r.d[0] = 0x0006; + Execute68kTrap(0xa06e, &r); // SFindStruct() + uint32 p = ReadMacInt32(sp + spPointer) - ROMBaseMac; + ROMBaseHost[p + 8] = i->bytes_per_row >> 8; + ROMBaseHost[p + 9] = i->bytes_per_row; + ROMBaseHost[p + 14] = i->y >> 8; + ROMBaseHost[p + 15] = i->y; + ROMBaseHost[p + 16] = i->x >> 8; + ROMBaseHost[p + 17] = i->x; + + // Update sResource + WriteMacInt8(sp + spID, ReadMacInt8(dce + dCtlSlotId)); + r.d[0] = 0x002b; + Execute68kTrap(0xa06e, &r); // SUpdateSRT() + + // Update frame buffer base in DCE + WriteMacInt32(dce + dCtlDevBase, frame_base); } - WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); + D(bug(" base %08x\n", VidLocal.desc->mac_frame_base)); return noErr; } @@ -332,37 +421,79 @@ int16 VideoDriverStatus(uint32 pb, uint32 dce) WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); return noErr; - // case cscGetEntries: + case cscGetEntries: { // Read palette + D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); - case cscGetPageCnt: // Get number of pages - D(bug(" GetPageCnt -> 1\n")); + uint8 *s_pal; // Source palette + uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette + uint16 start = ReadMacInt16(param + csStart); + uint16 count = ReadMacInt16(param + csCount); + if (d_pal == 0 || count > 255) + return paramErr; + + if (start == 0xffff) { // Indexed + for (uint32 i=0; i<=count; i++) { + s_pal = VidLocal.palette + (ReadMacInt16(d_pal) & 0xff) * 3; + uint8 red = *s_pal++; + uint8 green = *s_pal++; + uint8 blue = *s_pal++; + WriteMacInt16(d_pal + 2, red * 0x0101); + WriteMacInt16(d_pal + 4, green * 0x0101); + WriteMacInt16(d_pal + 6, blue * 0x0101); + d_pal += 8; + } + } else { // Sequential + if (start + count > 255) + return paramErr; + s_pal = VidLocal.palette + start * 3; + for (uint32 i=0; i<=count; i++) { + uint8 red = *s_pal++; + uint8 green = *s_pal++; + uint8 blue = *s_pal++; + WriteMacInt16(d_pal + 2, red * 0x0101); + WriteMacInt16(d_pal + 4, green * 0x0101); + WriteMacInt16(d_pal + 6, blue * 0x0101); + d_pal += 8; + } + } + return noErr; + } + + case cscGetPages: // Get number of pages + D(bug(" GetPages -> 1\n")); WriteMacInt16(param + csPage, 1); return noErr; - case cscGetPageBase: // Get page base address - D(bug(" GetPageBase -> %08x\n", VidLocal.desc->mac_frame_base)); + case cscGetBaseAddress: // Get page base address + D(bug(" GetBaseAddress -> %08x\n", VidLocal.desc->mac_frame_base)); WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); - return noErr; + if (ReadMacInt16(param + csPage)) + return paramErr; + else + return noErr; case cscGetGray: // Get luminance mapping flag D(bug(" GetGray -> %d\n", VidLocal.luminance_mapping)); - WriteMacInt8(param, VidLocal.luminance_mapping ? 1 : 0); + WriteMacInt16(param, VidLocal.luminance_mapping ? 0x0100 : 0); return noErr; case cscGetInterrupt: // Get interrupt disable flag D(bug(" GetInterrupt -> %d\n", VidLocal.interrupts_enabled)); - WriteMacInt8(param, VidLocal.interrupts_enabled ? 0 : 1); + WriteMacInt16(param, VidLocal.interrupts_enabled ? 0 : 0x0100); return noErr; - // case cscGetGamma: + case cscGetGamma: + D(bug(" GetGamma -> \n")); + //!! + return statusErr; case cscGetDefaultMode: // Get default color depth D(bug(" GetDefaultMode -> %04x\n", VidLocal.preferred_mode)); WriteMacInt16(param + csMode, VidLocal.preferred_mode); return noErr; - case cscGetCurMode: // Get current video mode (depth and resolution) - D(bug(" GetCurMode -> %04x/%08x\n", VidLocal.current_mode, VidLocal.current_id)); + case cscGetCurrentMode: // Get current video mode (depth and resolution) + D(bug(" GetCurMode -> %04x/%08x, base %08x\n", VidLocal.current_mode, VidLocal.current_id, VidLocal.desc->mac_frame_base)); WriteMacInt16(param + csMode, VidLocal.current_mode); WriteMacInt32(param + csData, VidLocal.current_id); WriteMacInt16(param + csPage, 0); @@ -371,16 +502,31 @@ int16 VideoDriverStatus(uint32 pb, uint32 dce) case cscGetConnection: // Get monitor information D(bug(" GetConnection\n")); - WriteMacInt16(param + csDisplayType, 6); // 21" Multiscan - WriteMacInt8(param + csConnectTaggedType, 6); - WriteMacInt8(param + csConnectTaggedData, 0x23); - WriteMacInt32(param + csConnectFlags, 0x03); // All modes valid and safe + WriteMacInt16(param + csDisplayType, 8); // Modeless connection + WriteMacInt8(param + csConnectTaggedType, 0); + WriteMacInt8(param + csConnectTaggedData, 0); + WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging WriteMacInt32(param + csDisplayComponent, 0); return noErr; + case cscGetModeTiming: { // Get video timing for specified resolution + uint32 id = ReadMacInt32(param + csTimingMode); + D(bug(" GetModeTiming %08x\n", id)); + if (!has_resolution(id)) + return paramErr; + + WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l')); + WriteMacInt32(param + csTimingData, 0); // unknown + uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel + if (id == VidLocal.preferred_id) + flags |= 4; // default mode + WriteMacInt32(param + csTimingFlags, flags); + return noErr; + } + case cscGetModeBaseAddress: // Get frame buffer base address - D(bug(" GetModeBaseAddress -> %08x\n", VidLocal.desc->mac_frame_base)); - WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); // Base address of video RAM for the current DisplayModeID and relative bit depth + D(bug(" GetModeBaseAddress -> base %08x\n", VidLocal.desc->mac_frame_base)); + WriteMacInt32(param + csBaseAddr, VidLocal.desc->mac_frame_base); return noErr; case cscGetPreferredConfiguration: // Get default video mode (depth and resolution) @@ -427,10 +573,6 @@ int16 VideoDriverStatus(uint32 pb, uint32 dce) WriteMacInt32(param + csVerticalLines, y); WriteMacInt32(param + csRefreshRate, 75 << 16); WriteMacInt16(param + csMaxDepthMode, DepthToAppleMode(max_depth_of_resolution(id))); - uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel - if (id == VidLocal.preferred_id) - flags |= 4; // default mode - WriteMacInt32(param + csResolutionFlags, flags); return noErr; } @@ -452,7 +594,7 @@ int16 VideoDriverStatus(uint32 pb, uint32 dce) WriteMacInt16(vp + vpVersion, 0); WriteMacInt16(vp + vpPackType, 0); WriteMacInt32(vp + vpPackSize, 0); - WriteMacInt32(vp + vpHRes, 0x00480000); + WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi WriteMacInt32(vp + vpVRes, 0x00480000); uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type; switch (i->depth) { @@ -500,21 +642,6 @@ int16 VideoDriverStatus(uint32 pb, uint32 dce) return paramErr; // specified resolution/depth not supported } - case cscGetModeTiming: { // Get video timing for specified resolution - uint32 id = ReadMacInt32(param + csTimingMode); - D(bug(" GetModeTiming %08x\n", id)); - if (!has_resolution(id)) - return paramErr; - - WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l')); - WriteMacInt32(param + csTimingData, 0); // unknown - uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel - if (id == VidLocal.preferred_id) - flags |= 4; // default mode - WriteMacInt32(param + csTimingFlags, flags); - return noErr; - } - default: printf("WARNING: Unknown VideoDriverStatus(%d)\n", code); return statusErr;