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.
This commit is contained in:
cebix 2001-06-28 21:20:02 +00:00
parent 0fe2584d92
commit 0cf3f32b7d
14 changed files with 750 additions and 556 deletions

View File

@ -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

View File

@ -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

View File

@ -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)."},

View File

@ -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,

View File

@ -24,6 +24,207 @@
// Note: this file is #include'd in video_x.cpp
#ifdef ENABLE_VOSF
#include <fcntl.h>
#include <sys/mman.h>
#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 <video_vosf.h> 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++) {

View File

@ -52,13 +52,6 @@
# include <sys/mman.h>
#endif
#ifdef ENABLE_VOSF
# include <fcntl.h>
# include <sys/mman.h>
# 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<video_mode *>(&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 <video_vosf.h> 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<video_mode>::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) {

View File

@ -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<video_mode> VideoModes;
extern std::vector<video_mode> VideoModes;
// Description for one (possibly virtual) monitor
struct monitor_desc {

View File

@ -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

View File

@ -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

View File

@ -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)
*/

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -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<video_mode>::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; y<VidLocal.desc->mode.y; y++) {
for (uint32 x=0; x<VidLocal.desc->mode.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<video_mode>::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;