--- BasiliskII/src/Unix/video_x.cpp 2001/07/03 15:59:47 1.51 +++ BasiliskII/src/Unix/video_x.cpp 2004/11/08 21:07:07 1.72 @@ -1,7 +1,7 @@ /* * video_x.cpp - Video/graphics emulation, X11 specific stuff * - * Basilisk II (C) 1997-2001 Christian Bauer + * Basilisk II (C) 1997-2004 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,8 @@ #include #include +#include + #ifdef HAVE_PTHREADS # include #endif @@ -60,11 +62,15 @@ #include "prefs.h" #include "user_strings.h" #include "video.h" +#include "video_blit.h" #define DEBUG 0 #include "debug.h" +// Supported video modes +static vector VideoModes; + // Display types enum { DISPLAY_WINDOW, // X11 window, using MIT SHM extensions if possible @@ -74,7 +80,7 @@ enum { // Constants const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; -static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask; +static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask; static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask; @@ -87,9 +93,11 @@ static int display_type = DISPLAY_WINDOW static bool local_X11; // Flag: X server running on local machine? static uint8 *the_buffer = NULL; // Mac frame buffer (where MacOS draws into) static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer (for refreshed modes) +static uint32 the_buffer_size; // Size of allocated the_buffer static bool redraw_thread_active = false; // Flag: Redraw thread installed #ifdef HAVE_PTHREADS +static pthread_attr_t redraw_thread_attr; // Redraw thread attributes static volatile bool redraw_thread_cancel; // Flag: Cancel Redraw thread static pthread_t redraw_thread; // Redraw thread #endif @@ -115,20 +123,28 @@ static bool use_keycodes = false; // static int keycode_table[256]; // X keycode -> Mac keycode translation table // X11 variables +char *x_display_name = NULL; // X11 display name +Display *x_display = NULL; // X11 display handle static int screen; // Screen number -static int xdepth; // Depth of X screen static Window rootwin; // Root window and our window -static XVisualInfo visualInfo; -static Visual *vis; -static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) +static int num_depths = 0; // Number of available X depths +static int *avail_depths = NULL; // List of available X depths static XColor black, white; static unsigned long black_pixel, white_pixel; static int eventmask; +static int xdepth; // Depth of X screen +static VisualFormat visualFormat; +static XVisualInfo visualInfo; +static Visual *vis; +static int color_class; + static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes -static XColor palette[256]; // Color palette to be used as CLUT and gamma table -static bool palette_changed = false; // Flag: Palette changed, redraw thread must set new colors +static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) + +static XColor x_palette[256]; // Color palette to be used as CLUT and gamma table +static bool x_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors #ifdef ENABLE_FBDEV_DGA static int fbdev_fd = -1; @@ -141,9 +157,9 @@ static int num_x_video_modes; // Mutex to protect palette #ifdef HAVE_PTHREADS -static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER; -#define LOCK_PALETTE pthread_mutex_lock(&palette_lock) -#define UNLOCK_PALETTE pthread_mutex_unlock(&palette_lock) +static pthread_mutex_t x_palette_lock = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_PALETTE pthread_mutex_lock(&x_palette_lock) +#define UNLOCK_PALETTE pthread_mutex_unlock(&x_palette_lock) #else #define LOCK_PALETTE #define UNLOCK_PALETTE @@ -172,26 +188,175 @@ 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; +extern void *vm_acquire_mac(size_t size); // From sys_unix.cpp extern void SysMountFirstFloppy(void); /* + * monitor_desc subclass for X11 display + */ + +class X11_monitor_desc : public monitor_desc { +public: + X11_monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {} + ~X11_monitor_desc() {} + + virtual void switch_to_current_mode(void); + virtual void set_palette(uint8 *pal, int num); + + bool video_open(void); + void video_close(void); +}; + + +/* * Utility functions */ +// Map video_mode depth ID to numerical depth value +static inline int depth_of_video_mode(video_mode const & mode) +{ + int depth = -1; + switch (mode.depth) { + case VDEPTH_1BIT: + depth = 1; + break; + case VDEPTH_2BIT: + depth = 2; + break; + case VDEPTH_4BIT: + depth = 4; + break; + case VDEPTH_8BIT: + depth = 8; + break; + case VDEPTH_16BIT: + depth = 16; + break; + case VDEPTH_32BIT: + depth = 32; + break; + default: + abort(); + } + return depth; +} + // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals) static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue) { return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift); } +// Do we have a visual for handling the specified Mac depth? If so, set the +// global variables "xdepth", "visualInfo", "vis" and "color_class". +static bool find_visual_for_depth(video_depth depth) +{ + D(bug("have_visual_for_depth(%d)\n", 1 << depth)); + + // 1-bit works always and uses default visual + if (depth == VDEPTH_1BIT) { + vis = DefaultVisual(x_display, screen); + visualInfo.visualid = XVisualIDFromVisual(vis); + int num = 0; + XVisualInfo *vi = XGetVisualInfo(x_display, VisualIDMask, &visualInfo, &num); + visualInfo = vi[0]; + XFree(vi); + xdepth = visualInfo.depth; + color_class = visualInfo.c_class; + D(bug(" found visual ID 0x%02x, depth %d\n", visualInfo.visualid, xdepth)); + return true; + } + + // Calculate minimum and maximum supported X depth + int min_depth = 1, max_depth = 32; + switch (depth) { +#ifdef ENABLE_VOSF + case VDEPTH_2BIT: + case VDEPTH_4BIT: // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit + case VDEPTH_8BIT: + min_depth = 8; + max_depth = 32; + break; +#else + case VDEPTH_2BIT: + case VDEPTH_4BIT: // 2/4-bit requires VOSF blitters + return false; + case VDEPTH_8BIT: // 8-bit without VOSF requires an 8-bit visual + min_depth = 8; + max_depth = 8; + break; +#endif + case VDEPTH_16BIT: // 16-bit requires a 15/16-bit visual + min_depth = 15; + max_depth = 16; + break; + case VDEPTH_32BIT: // 32-bit requires a 24/32-bit visual + min_depth = 24; + max_depth = 32; + break; + } + D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth)); + + // Try to find a visual for one of the color depths + bool visual_found = false; + for (int i=0; i max_depth) + continue; + + // Determine best color class for this depth + switch (xdepth) { + case 1: // Try StaticGray or StaticColor + if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo) + || XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo)) + visual_found = true; + break; + case 8: // Need PseudoColor + if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo)) + visual_found = true; + break; + case 15: + case 16: + case 24: + case 32: // Try DirectColor first, as this will allow gamma correction + if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo) + || XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo)) + visual_found = true; + break; + default: + D(bug(" not a supported depth\n")); + break; + } + } + if (!visual_found) + return false; + + // Visual was found + vis = visualInfo.visual; + color_class = visualInfo.c_class; + D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth)); +#if DEBUG + switch (color_class) { + case StaticGray: D(bug("StaticGray\n")); break; + case GrayScale: D(bug("GrayScale\n")); break; + case StaticColor: D(bug("StaticColor\n")); break; + case PseudoColor: D(bug("PseudoColor\n")); break; + case TrueColor: D(bug("TrueColor\n")); break; + case DirectColor: D(bug("DirectColor\n")); break; + } +#endif + return true; +} + // 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) { @@ -217,7 +382,7 @@ static void add_window_modes(video_depth } // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) -static void set_mac_frame_buffer(video_depth depth, bool native_byte_order) +static void set_mac_frame_buffer(X11_monitor_desc &monitor, video_depth depth, bool native_byte_order) { #if !REAL_ADDRESSING && !DIRECT_ADDRESSING int layout = FLAYOUT_DIRECT; @@ -229,17 +394,17 @@ static void set_mac_frame_buffer(video_d MacFrameLayout = layout; else MacFrameLayout = FLAYOUT_DIRECT; - VideoMonitor.mac_frame_base = MacFrameBaseMac; + monitor.set_mac_frame_base(MacFrameBaseMac); // Set variables used by UAE memory banking + const video_mode &mode = monitor.get_current_mode(); MacFrameBaseHost = the_buffer; - MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; + MacFrameSize = mode.bytes_per_row * mode.y; InitFrameBufferMapping(); #else - VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); - D(bug("Host frame buffer = %p, ", the_buffer)); + monitor.set_mac_frame_base(Host2MacAddr(the_buffer)); #endif - D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base)); + D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base())); } // Set window name and class @@ -317,7 +482,7 @@ static int error_handler(Display *d, XEr class driver_base { public: - driver_base(); + driver_base(X11_monitor_desc &m); virtual ~driver_base(); virtual void update_palette(void); @@ -326,12 +491,20 @@ public: virtual void toggle_mouse_grab(void) {} virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); } + void disable_mouse_accel(void); + void restore_mouse_accel(void); + virtual void grab_mouse(void) {} virtual void ungrab_mouse(void) {} public: + X11_monitor_desc &monitor; // Associated video monitor + const video_mode &mode; // Video mode handled by the driver + bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer) Window w; // The window we draw into + + int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration }; class driver_window; @@ -345,7 +518,7 @@ class driver_window : public driver_base friend void update_display_static(driver_window *drv); public: - driver_window(const video_mode &mode); + driver_window(X11_monitor_desc &monitor); ~driver_window(); void toggle_mouse_grab(void); @@ -370,16 +543,18 @@ static driver_base *drv = NULL; // Point # include "video_vosf.h" #endif -driver_base::driver_base() - : init_ok(false), w(0) +driver_base::driver_base(X11_monitor_desc &m) + : monitor(m), mode(m.get_current_mode()), init_ok(false), w(0) { the_buffer = NULL; the_buffer_copy = NULL; + XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold); } driver_base::~driver_base() { ungrab_mouse(); + restore_mouse_accel(); if (w) { XUnmapWindow(x_display, w); @@ -403,12 +578,20 @@ driver_base::~driver_base() } #ifdef ENABLE_VOSF else { - if (the_buffer != (uint8 *)VM_MAP_FAILED) { + // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will + if (the_buffer != VM_MAP_FAILED) { + D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size)); vm_release(the_buffer, the_buffer_size); the_buffer = NULL; } - if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) { - vm_release(the_buffer_copy, the_buffer_size); + if (the_host_buffer) { + D(bug(" freeing the_host_buffer at %p\n", the_host_buffer)); + free(the_host_buffer); + the_host_buffer = NULL; + } + if (the_buffer_copy) { + D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy)); + free(the_buffer_copy); the_buffer_copy = NULL; } } @@ -418,26 +601,36 @@ driver_base::~driver_base() // Palette has changed void driver_base::update_palette(void) { - if (cmap[0] && cmap[1]) { - int num = 256; - if (IsDirectMode(VideoMonitor.mode)) - num = vis->map_entries; // Palette is gamma table - else if (vis->c_class == DirectColor) + if (color_class == PseudoColor || color_class == DirectColor) { + int num = vis->map_entries; + if (!IsDirectMode(monitor.get_current_mode()) && color_class == DirectColor) return; // Indexed mode on true color screen, don't set CLUT - XStoreColors(x_display, cmap[0], palette, num); - XStoreColors(x_display, cmap[1], palette, num); + XStoreColors(x_display, cmap[0], x_palette, num); + XStoreColors(x_display, cmap[1], x_palette, num); } XSync(x_display, false); } +// Disable mouse acceleration +void driver_base::disable_mouse_accel(void) +{ + XChangePointerControl(x_display, True, False, 1, 1, 0); +} + +// Restore mouse acceleration to original value +void driver_base::restore_mouse_accel(void) +{ + XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold); +} + /* * Windowed display driver */ // Open display -driver_window::driver_window(const video_mode &mode) - : gc(0), img(NULL), have_shm(false), mouse_grabbed(false), mac_cursor(0) +driver_window::driver_window(X11_monitor_desc &m) + : driver_base(m), gc(0), img(NULL), have_shm(false), mac_cursor(0), mouse_grabbed(false) { int width = mode.x, height = mode.y; int aligned_width = (width + 15) & ~15; @@ -446,13 +639,17 @@ driver_window::driver_window(const video // Set absolute mouse mode ADBSetRelMouseMode(mouse_grabbed); - // Create window + // Create window (setting background_pixel, border_pixel and colormap is + // mandatory when using a non-default visual; in 1-bit mode we use the + // default visual, so we can also use the default colormap) XSetWindowAttributes wattr; wattr.event_mask = eventmask = win_eventmask; - wattr.background_pixel = black_pixel; - wattr.colormap = (mode.depth == VDEPTH_1BIT && vis->c_class == PseudoColor ? DefaultColormap(x_display, screen) : cmap[0]); + wattr.background_pixel = (vis == DefaultVisual(x_display, screen) ? black_pixel : 0); + wattr.border_pixel = 0; + wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]); w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, - InputOutput, vis, CWEventMask | CWBackPixel | (vis->c_class == PseudoColor || vis->c_class == DirectColor ? CWColormap : 0), &wattr); + InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr); + D(bug(" window created\n")); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); @@ -476,10 +673,12 @@ driver_window::driver_window(const video XFree(hints); } } + D(bug(" window attributes set\n")); // Show window XMapWindow(x_display, w); wait_mapped(w); + D(bug(" window mapped\n")); // 1-bit mode is big-endian; if the X server is little-endian, we can't // use SHM because that doesn't allow changing the image byte order @@ -490,6 +689,7 @@ driver_window::driver_window(const video // Create SHM image ("height + 2" for safety) img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height); + D(bug(" shm image created\n")); 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; @@ -504,11 +704,13 @@ driver_window::driver_window(const video if (shm_error) { shmdt(shminfo.shmaddr); XDestroyImage(img); + img = NULL; shminfo.shmid = -1; } else { have_shm = true; shmctl(shminfo.shmid, IPC_RMID, 0); } + D(bug(" shm image attached\n")); } // Create normal X image if SHM doesn't work ("height + 2" for safety) @@ -516,6 +718,7 @@ driver_window::driver_window(const video int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth))); the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * 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); + D(bug(" X image created\n")); } if (need_msb_image) { @@ -524,14 +727,17 @@ driver_window::driver_window(const video } #ifdef ENABLE_VOSF + use_vosf = true; // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer_copy; the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line); - the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); + the_buffer_copy = (uint8 *)malloc(the_buffer_size); + D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); #else // Allocate memory for frame buffer the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line); + D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); #endif // Create GC @@ -553,12 +759,11 @@ driver_window::driver_window(const video native_byte_order = (XImageByteOrder(x_display) == LSBFirst); #endif #ifdef ENABLE_VOSF - Screen_blitter_init(&visualInfo, native_byte_order, mode.depth); + Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode)); #endif - // Set VideoMonitor - VideoMonitor.mode = mode; - set_mac_frame_buffer(mode.depth, native_byte_order); + // Set frame buffer base + set_mac_frame_buffer(monitor, mode.depth, native_byte_order); // Everything went well init_ok = true; @@ -567,11 +772,22 @@ driver_window::driver_window(const video // Close display driver_window::~driver_window() { - if (img) - XDestroyImage(img); if (have_shm) { XShmDetach(x_display, &shminfo); +#ifdef ENABLE_VOSF + the_host_buffer = NULL; // don't free() in driver_base dtor +#else the_buffer_copy = NULL; // don't free() in driver_base dtor +#endif + } + if (img) { + if (!have_shm) + img->data = NULL; + XDestroyImage(img); + } + if (have_shm) { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); } if (gc) XFreeGC(x_display, gc); @@ -598,9 +814,9 @@ void driver_window::grab_mouse(void) Delay_usec(100000); } if (result == GrabSuccess) { - ADBSetRelMouseMode(mouse_grabbed = true); XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED)); - XSync(x_display, false); + ADBSetRelMouseMode(mouse_grabbed = true); + disable_mouse_accel(); } } @@ -611,6 +827,7 @@ void driver_window::ungrab_mouse(void) XUngrabPointer(x_display, CurrentTime); XStoreName(x_display, w, GetString(STR_WINDOW_TITLE)); ADBSetRelMouseMode(mouse_grabbed = false); + restore_mouse_accel(); } } @@ -626,7 +843,7 @@ void driver_window::mouse_moved(int x, i // Warped mouse motion (this code is taken from SDL) // Post first mouse event - int width = VideoMonitor.mode.x, height = VideoMonitor.mode.y; + int width = monitor.get_current_mode().x, height = monitor.get_current_mode().y; int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y; mouse_last_x = x; mouse_last_y = y; ADBMouseMoved(delta_x, delta_y); @@ -663,7 +880,7 @@ void driver_window::mouse_moved(int x, i class driver_dga : public driver_base { public: - driver_dga(); + driver_dga(X11_monitor_desc &monitor); ~driver_dga(); void suspend(void); @@ -674,8 +891,8 @@ private: void *fb_save; // Saved frame buffer for suspend/resume }; -driver_dga::driver_dga() - : suspend_win(0), fb_save(NULL) +driver_dga::driver_dga(X11_monitor_desc &m) + : driver_base(m), suspend_win(0), fb_save(NULL) { } @@ -696,9 +913,9 @@ void driver_dga::suspend(void) LOCK_FRAME_BUFFER; // Save frame buffer - fb_save = malloc(VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row); + fb_save = malloc(mode.y * mode.bytes_per_row); if (fb_save) - memcpy(fb_save, the_buffer, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row); + memcpy(fb_save, the_buffer, mode.y * mode.bytes_per_row); // Close full screen display #ifdef ENABLE_XF86_DGA @@ -706,6 +923,7 @@ void driver_dga::suspend(void) #endif XUngrabPointer(x_display, CurrentTime); XUngrabKeyboard(x_display, CurrentTime); + restore_mouse_accel(); XUnmapWindow(x_display, w); wait_unmapped(w); @@ -735,6 +953,7 @@ void driver_dga::resume(void) XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0); XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + disable_mouse_accel(); #ifdef ENABLE_XF86_DGA XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); XF86DGASetViewPort(x_display, screen, 0, 0); @@ -749,7 +968,7 @@ void driver_dga::resume(void) LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; - memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); + memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } #endif @@ -759,7 +978,7 @@ void driver_dga::resume(void) // Don't copy fb_save to the temporary frame buffer in VOSF mode if (!use_vosf) #endif - memcpy(the_buffer, fb_save, VideoMonitor.mode.y * VideoMonitor.mode.bytes_per_row); + memcpy(the_buffer, fb_save, mode.y * mode.bytes_per_row); free(fb_save); fb_save = NULL; } @@ -781,12 +1000,12 @@ const char FBDEVICE_FILE_NAME[] = "/dev/ class driver_fbdev : public driver_dga { public: - driver_fbdev(const video_mode &mode); + driver_fbdev(X11_monitor_desc &monitor); ~driver_fbdev(); }; // Open display -driver_fbdev::driver_fbdev(const video_mode &mode) +driver_fbdev::driver_fbdev(X11_monitor_desc &m) : driver_dga(m) { int width = mode.x, height = mode.y; @@ -834,7 +1053,7 @@ driver_fbdev::driver_fbdev(const video_m if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\0')) continue; - if ((sscanf(line, "%19s %d %x", &fb_name, &fb_depth, &fb_offset) == 3) + if ((sscanf(line, "%19s %d %x", fb_name, &fb_depth, &fb_offset) == 3) && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) { device_found = true; break; @@ -881,13 +1100,15 @@ driver_fbdev::driver_fbdev(const video_m XGrabPointer(x_display, w, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, w, None, CurrentTime); + disable_mouse_accel(); // 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) { + the_buffer_size = height * bytes_per_row; + if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) { + if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) { char str[256]; sprintf(str, GetString(STR_FBDEV_MMAP_ERR), strerror(errno)); ErrorAlert(str); @@ -899,25 +1120,24 @@ driver_fbdev::driver_fbdev(const video_m #if REAL_ADDRESSING || DIRECT_ADDRESSING // Screen_blitter_init() returns TRUE if VOSF is mandatory // i.e. the framebuffer update function is not Blit_Copy_Raw - use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth); + use_vosf = Screen_blitter_init(visualFormat, true, mode.depth); if (use_vosf) { // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); - the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer_copy = (uint8 *)malloc(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); } #else use_vosf = false; #endif #endif - // Set VideoMonitor - VideoModes[0].bytes_per_row = bytes_per_row; - VideoModes[0].depth = DepthModeForPixelDepth(fb_depth); - VideoMonitor.mode = mode; - set_mac_frame_buffer(mode.depth, true); + // Set frame buffer base + const_cast(&mode)->bytes_per_row = bytes_per_row; + const_cast(&mode)->depth = DepthModeForPixelDepth(fb_depth); + set_mac_frame_buffer(monitor, mode.depth, true); // Everything went well init_ok = true; @@ -926,6 +1146,22 @@ driver_fbdev::driver_fbdev(const video_m // Close display driver_fbdev::~driver_fbdev() { + if (!use_vosf) { + if (the_buffer != MAP_FAILED) { + // don't free() the screen buffer in driver_base dtor + munmap(the_buffer, the_buffer_size); + the_buffer = NULL; + } + } +#ifdef ENABLE_VOSF + else { + if (the_host_buffer != MAP_FAILED) { + // don't free() the screen buffer in driver_base dtor + munmap(the_host_buffer, the_buffer_size); + the_host_buffer = NULL; + } + } +#endif } #endif @@ -937,7 +1173,7 @@ driver_fbdev::~driver_fbdev() class driver_xf86dga : public driver_dga { public: - driver_xf86dga(const video_mode &mode); + driver_xf86dga(X11_monitor_desc &monitor); ~driver_xf86dga(); void update_palette(void); @@ -948,8 +1184,8 @@ private: }; // Open display -driver_xf86dga::driver_xf86dga(const video_mode &mode) - : current_dga_cmap(0) +driver_xf86dga::driver_xf86dga(X11_monitor_desc &m) + : driver_dga(m), current_dga_cmap(0) { int width = mode.x, height = mode.y; @@ -976,9 +1212,11 @@ driver_xf86dga::driver_xf86dga(const vid XSetWindowAttributes wattr; wattr.event_mask = eventmask = dga_eventmask; wattr.override_redirect = True; + wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]); w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, - InputOutput, vis, CWEventMask | CWOverrideRedirect, &wattr); + InputOutput, vis, CWEventMask | CWOverrideRedirect | + (color_class == DirectColor ? CWColormap : 0), &wattr); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); @@ -995,6 +1233,7 @@ driver_xf86dga::driver_xf86dga(const vid XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0); XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + disable_mouse_accel(); int v_width, v_bank, v_size; XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size); @@ -1011,28 +1250,33 @@ driver_xf86dga::driver_xf86dga(const vid // Init blitting routines int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth); -#ifdef VIDEO_VOSF +#if ENABLE_VOSF + bool native_byte_order; +#ifdef WORDS_BIGENDIAN + native_byte_order = (XImageByteOrder(x_display) == MSBFirst); +#else + native_byte_order = (XImageByteOrder(x_display) == LSBFirst); +#endif #if REAL_ADDRESSING || DIRECT_ADDRESSING // Screen_blitter_init() returns TRUE if VOSF is mandatory // i.e. the framebuffer update function is not Blit_Copy_Raw - use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth); + use_vosf = Screen_blitter_init(visualFormat, native_byte_order, depth_of_video_mode(mode)); if (use_vosf) { // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); - the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size); - the_buffer = (uint8 *)vm_acquire(the_buffer_size); + the_buffer_copy = (uint8 *)malloc(the_buffer_size); + the_buffer = (uint8 *)vm_acquire_mac(the_buffer_size); } #else use_vosf = false; #endif #endif - // Set VideoMonitor + // Set frame buffer base const_cast(&mode)->bytes_per_row = bytes_per_row; - VideoMonitor.mode = mode; - set_mac_frame_buffer(mode.depth, true); + set_mac_frame_buffer(monitor, mode.depth, true); // Everything went well init_ok = true; @@ -1042,6 +1286,16 @@ driver_xf86dga::driver_xf86dga(const vid driver_xf86dga::~driver_xf86dga() { XF86DGADirectVideo(x_display, screen, 0); + if (!use_vosf) { + // don't free() the screen buffer in driver_base dtor + the_buffer = NULL; + } +#ifdef ENABLE_VOSF + else { + // don't free() the screen buffer in driver_base dtor + the_host_buffer = NULL; + } +#endif #ifdef ENABLE_XF86_VIDMODE if (has_vidmode) XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]); @@ -1053,7 +1307,7 @@ void driver_xf86dga::update_palette(void { driver_dga::update_palette(); current_dga_cmap ^= 1; - if (!IsDirectMode(VideoMonitor.mode) && cmap[current_dga_cmap]) + if (!IsDirectMode(monitor.get_current_mode()) && cmap[current_dga_cmap]) XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } @@ -1061,7 +1315,7 @@ void driver_xf86dga::update_palette(void void driver_xf86dga::resume(void) { driver_dga::resume(); - if (!IsDirectMode(VideoMonitor.mode)) + if (!IsDirectMode(monitor.get_current_mode())) XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } #endif @@ -1136,28 +1390,83 @@ static void keycode_init(void) } } -// Open display for specified mode -static bool video_open(const video_mode &mode) +// Open display for current mode +bool X11_monitor_desc::video_open(void) { + D(bug("video_open()\n")); + const video_mode &mode = get_current_mode(); + + // Find best available X visual + if (!find_visual_for_depth(mode.depth)) { + ErrorAlert(STR_NO_XVISUAL_ERR); + return false; + } + + // Build up visualFormat structure + visualFormat.depth = visualInfo.depth; + visualFormat.Rmask = visualInfo.red_mask; + visualFormat.Gmask = visualInfo.green_mask; + visualFormat.Bmask = visualInfo.blue_mask; + + // Create color maps + if (color_class == PseudoColor || color_class == DirectColor) { + cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); + cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); + } else { + cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocNone); + cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocNone); + } + + // Find pixel format of direct modes + if (color_class == DirectColor || color_class == TrueColor) { + rshift = gshift = bshift = 0; + rloss = gloss = bloss = 8; + uint32 mask; + for (mask=vis->red_mask; !(mask&1); mask>>=1) + ++rshift; + for (; mask&1; mask>>=1) + --rloss; + for (mask=vis->green_mask; !(mask&1); mask>>=1) + ++gshift; + for (; mask&1; mask>>=1) + --gloss; + for (mask=vis->blue_mask; !(mask&1); mask>>=1) + ++bshift; + for (; mask&1; mask>>=1) + --bloss; + } + + // Preset palette pixel values for CLUT or gamma table + if (color_class == DirectColor) { + int num = vis->map_entries; + for (int i=0; ic_class == DirectColor ? vis->map_entries : 256); + int num = (color_class == DirectColor ? vis->map_entries : 256); for (int i=0; ic_class == PseudoColor) - palette[i].pixel = i; - palette[i].flags = DoRed | DoGreen | DoBlue; - } - if (cmap[0] && cmap[1]) { - XStoreColors(x_display, cmap[0], palette, num); - XStoreColors(x_display, cmap[1], palette, num); + x_palette[i].red = c * 0x0101; + x_palette[i].green = c * 0x0101; + x_palette[i].blue = c * 0x0101; + } + if (color_class == PseudoColor || color_class == DirectColor) { + XStoreColors(x_display, cmap[0], x_palette, num); + XStoreColors(x_display, cmap[1], x_palette, num); } #ifdef ENABLE_VOSF // Load gray ramp to 8->16/32 expand map - if (!IsDirectMode(mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) + if (!IsDirectMode(mode) && xdepth > 8) for (int i=0; i<256; i++) ExpandMap[i] = map_rgb(i, i, i); #endif @@ -1165,16 +1474,16 @@ static bool video_open(const video_mode // Create display driver object of requested type switch (display_type) { case DISPLAY_WINDOW: - drv = new driver_window(mode); + drv = new driver_window(*this); break; #ifdef ENABLE_FBDEV_DGA case DISPLAY_DGA: - drv = new driver_fbdev(mode); + drv = new driver_fbdev(*this); break; #endif #ifdef ENABLE_XF86_DGA case DISPLAY_DGA: - drv = new driver_xf86dga(mode); + drv = new driver_xf86dga(*this); break; #endif } @@ -1188,17 +1497,11 @@ static bool video_open(const video_mode #ifdef ENABLE_VOSF if (use_vosf) { - // Initialize the mainBuffer structure - if (!video_init_buffer()) { + // Initialize the VOSF system + if (!video_vosf_init(*this)) { ErrorAlert(STR_VOSF_INIT_ERR); return false; } - - // Initialize the handler for SIGSEGV - if (!sigsegv_install_handler(screen_fault_handler)) { - ErrorAlert("Could not initialize Video on SEGV signals"); - return false; - } } #endif @@ -1212,7 +1515,8 @@ static bool video_open(const video_mode // Start redraw/input thread #ifdef HAVE_PTHREADS redraw_thread_cancel = false; - redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0); + Set_pthread_attr(&redraw_thread_attr, 0); + redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0); if (!redraw_thread_active) { printf("FATAL: cannot create redraw thread\n"); return false; @@ -1249,9 +1553,14 @@ bool VideoInit(bool classic) // Find screen and root window screen = XDefaultScreen(x_display); rootwin = XRootWindow(x_display, screen); - - // Get screen depth - xdepth = DefaultDepth(x_display, screen); + + // Get sorted list of available depths + avail_depths = XListDepths(x_display, screen, &num_depths); + if (avail_depths == NULL) { + ErrorAlert(STR_UNSUPP_DEPTH_ERR); + return false; + } + std::sort(avail_depths, avail_depths + num_depths); #ifdef ENABLE_FBDEV_DGA // Frame buffer name @@ -1291,71 +1600,6 @@ bool VideoInit(bool classic) black_pixel = BlackPixel(x_display, screen); white_pixel = WhitePixel(x_display, screen); - // Get appropriate visual - int color_class; - switch (xdepth) { - case 1: - color_class = StaticGray; - break; - case 8: - color_class = PseudoColor; - break; - case 15: - case 16: - case 24: - case 32: // Try DirectColor first, as this will allow gamma correction - color_class = DirectColor; - if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) - color_class = TrueColor; - break; - default: - ErrorAlert(STR_UNSUPP_DEPTH_ERR); - return false; - } - if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) { - ErrorAlert(STR_NO_XVISUAL_ERR); - return false; - } - if (visualInfo.depth != xdepth) { - ErrorAlert(STR_NO_XVISUAL_ERR); - return false; - } - vis = visualInfo.visual; - - // Create color maps - if (color_class == PseudoColor || color_class == DirectColor) { - cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); - cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); - } - - // Find pixel format of direct modes - if (color_class == DirectColor || color_class == TrueColor) { - rshift = gshift = bshift = 0; - rloss = gloss = bloss = 8; - uint32 mask; - for (mask=vis->red_mask; !(mask&1); mask>>=1) - ++rshift; - for (; mask&1; mask>>=1) - --rloss; - for (mask=vis->green_mask; !(mask&1); mask>>=1) - ++gshift; - for (; mask&1; mask>>=1) - --gloss; - for (mask=vis->blue_mask; !(mask&1); mask>>=1) - ++bshift; - for (; mask&1; mask>>=1) - --bloss; - } - - // Preset palette pixel values for gamma table - if (color_class == DirectColor) { - int num = vis->map_entries; - for (int i=0; i VDEPTH_8BIT) { - add_window_modes(VDEPTH_2BIT); // 2, 4 and 8-bit modes are also possible on 16/32-bit screens with VOSF blitters - add_window_modes(VDEPTH_4BIT); - add_window_modes(VDEPTH_8BIT); + for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) { + if (find_visual_for_depth(video_depth(d))) + add_window_modes(video_depth(d)); } -#endif - add_window_modes(default_depth); } } else add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth); + if (VideoModes.empty()) { + ErrorAlert(STR_NO_XVISUAL_ERR); + return false; + } - // 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, end = VideoModes.end(); - for (i = VideoModes.begin(); i != end; ++i) { - if (i->x == default_width && i->y == default_height && i->depth == default_depth) - return video_open(*i); + // Find requested default mode with specified dimensions + uint32 default_id; + std::vector::const_iterator i, end = VideoModes.end(); + for (i = VideoModes.begin(); i != end; ++i) { + if (i->x == default_width && i->y == default_height && i->depth == default_depth) { + default_id = i->resolution_id; + break; } - return video_open(VideoModes[0]); } + if (i == end) { // not found, use first available mode + default_depth = VideoModes[0].depth; + default_id = VideoModes[0].resolution_id; + } + +#if DEBUG + D(bug("Available video modes:\n")); + for (i = VideoModes.begin(); i != end; ++i) { + int bits = 1 << i->depth; + if (bits == 16) + bits = 15; + else if (bits == 32) + bits = 24; + D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits)); + } +#endif + + // Create X11_monitor_desc for this (the only) display + X11_monitor_desc *monitor = new X11_monitor_desc(VideoModes, default_depth, default_id); + VideoMonitors.push_back(monitor); + + // Open display + return monitor->video_open(); } @@ -1431,8 +1704,10 @@ bool VideoInit(bool classic) */ // Close display -static void video_close(void) +void X11_monitor_desc::video_close(void) { + D(bug("video_close()\n")); + // Stop redraw thread #ifdef HAVE_PTHREADS if (redraw_thread_active) { @@ -1448,30 +1723,18 @@ static void video_close(void) // Unlock frame buffer UNLOCK_FRAME_BUFFER; XSync(x_display, false); + D(bug(" frame buffer unlocked\n")); #ifdef ENABLE_VOSF - // Deinitialize VOSF if (use_vosf) { - if (mainBuffer.pageInfo) { - free(mainBuffer.pageInfo); - mainBuffer.pageInfo = NULL; - } - if (mainBuffer.dirtyPages) { - free(mainBuffer.dirtyPages); - mainBuffer.dirtyPages = NULL; - } + // Deinitialize VOSF + video_vosf_exit(); } #endif // Close display delete drv; drv = NULL; -} - -void VideoExit(void) -{ - // Close display - video_close(); // Free colormaps if (cmap[0]) { @@ -1482,6 +1745,14 @@ void VideoExit(void) XFreeColormap(x_display, cmap[1]); cmap[1] = 0; } +} + +void VideoExit(void) +{ + // Close displays + vector::iterator i, end = VideoMonitors.end(); + for (i = VideoMonitors.begin(); i != end; ++i) + dynamic_cast(*i)->video_close(); #ifdef ENABLE_XF86_VIDMODE // Free video mode list @@ -1498,6 +1769,12 @@ void VideoExit(void) fbdev_fd = -1; } #endif + + // Free depth list + if (avail_depths) { + XFree(avail_depths); + avail_depths = NULL; + } } @@ -1533,31 +1810,32 @@ void VideoInterrupt(void) * Set palette */ -void video_set_palette(uint8 *pal, int num_in) +void X11_monitor_desc::set_palette(uint8 *pal, int num_in) { + const video_mode &mode = get_current_mode(); + LOCK_PALETTE; // Convert colors to XColor array int num_out = 256; - if (IsDirectMode(VideoMonitor.mode)) { + bool stretch = false; + if (IsDirectMode(mode)) { // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries num_out = vis->map_entries; + stretch = true; } - XColor *p = palette; + XColor *p = x_palette; for (int i=0; ired = pal[c*3 + 0] * 0x0101; p->green = pal[c*3 + 1] * 0x0101; p->blue = pal[c*3 + 2] * 0x0101; - if (vis->c_class == PseudoColor) - p->pixel = i; - p->flags = DoRed | DoGreen | DoBlue; p++; } #ifdef ENABLE_VOSF // Recalculate pixel color expansion map - if (!IsDirectMode(VideoMonitor.mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) { + if (!IsDirectMode(mode) && xdepth > 8) { for (int i=0; i<256; i++) { int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]); @@ -1567,12 +1845,12 @@ void video_set_palette(uint8 *pal, int n LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; - memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); + memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } #endif // Tell redraw thread to change palette - palette_changed = true; + x_palette_changed = true; UNLOCK_PALETTE; } @@ -1582,11 +1860,11 @@ void video_set_palette(uint8 *pal, int n * Switch video mode */ -void video_switch_to_mode(const video_mode &mode) +void X11_monitor_desc::switch_to_current_mode(void) { // Close and reopen display video_close(); - video_open(mode); + video_open(); if (drv == NULL) { ErrorAlert(STR_OPEN_WINDOW_ERR); @@ -1770,6 +2048,7 @@ static void handle_events(void) XNextEvent(x_display, &event); switch (event.type) { + // Mouse button case ButtonPress: { unsigned int button = event.xbutton.button; @@ -1802,6 +2081,12 @@ static void handle_events(void) drv->mouse_moved(event.xmotion.x, event.xmotion.y); break; + // Mouse entered window + case EnterNotify: + if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab) + drv->mouse_moved(event.xmotion.x, event.xmotion.y); + break; + // Keyboard case KeyPress: { int code = -1; @@ -1849,12 +2134,13 @@ static void handle_events(void) // Hidden parts exposed, force complete refresh of window case Expose: if (display_type == DISPLAY_WINDOW) { + const video_mode &mode = VideoMonitors[0]->get_current_mode(); #ifdef ENABLE_VOSF if (use_vosf) { // VOSF refresh LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; - memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); + memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } else #endif @@ -1865,7 +2151,7 @@ static void handle_events(void) updt_box[x1][y1] = true; nr_boxes = 16 * 16; } else // Static refresh - memset(the_buffer_copy, 0, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); + memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } break; @@ -1891,10 +2177,11 @@ static void update_display_dynamic(int t int y1, y2, y2s, y2a, i, x1, xm, xmo, ymo, yo, yi, yil, xi; int xil = 0; int rxm = 0, rxmo = 0; - int bytes_per_row = VideoMonitor.mode.bytes_per_row; - int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x; - int rx = VideoMonitor.mode.bytes_per_row / 16; - int ry = VideoMonitor.mode.y / 16; + const video_mode &mode = drv->monitor.get_current_mode(); + int bytes_per_row = mode.bytes_per_row; + int bytes_per_pixel = mode.bytes_per_row / mode.x; + int rx = mode.bytes_per_row / 16; + int ry = mode.y / 16; int max_box; y2s = sm_uptd[ticker % 8]; @@ -1948,7 +2235,7 @@ static void update_display_dynamic(int t 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 (VideoMonitor.mode.depth == VDEPTH_1BIT) { + if (mode.depth == VDEPTH_1BIT) { if (drv->have_shm) XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0); else @@ -1979,21 +2266,22 @@ static void update_display_dynamic(int t static void update_display_static(driver_window *drv) { // Incremental update code - int wide = 0, high = 0, x1, x2, y1, y2, i, j; - int bytes_per_row = VideoMonitor.mode.bytes_per_row; - int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x; + unsigned wide = 0, high = 0, x1, x2, y1, y2, i, j; + const video_mode &mode = drv->monitor.get_current_mode(); + int bytes_per_row = mode.bytes_per_row; + int bytes_per_pixel = mode.bytes_per_row / mode.x; uint8 *p, *p2; // Check for first line from top and first line from bottom that have changed y1 = 0; - for (j=0; j=y1; j--) { + for (j=mode.y-1; j>=y1; j--) { if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) { y2 = j; break; @@ -2003,8 +2291,8 @@ static void update_display_static(driver // Check for first column from left and first column from right that have changed if (high) { - if (VideoMonitor.mode.depth == VDEPTH_1BIT) { - x1 = VideoMonitor.mode.x - 1; + if (mode.depth == VDEPTH_1BIT) { + x1 = mode.x - 1; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; @@ -2022,7 +2310,7 @@ static void update_display_static(driver p2 = &the_buffer_copy[j * bytes_per_row]; p += bytes_per_row; p2 += bytes_per_row; - for (i=(VideoMonitor.mode.x>>3); i>(x2>>3); i--) { + for (i=(mode.x>>3); i>(x2>>3); i--) { p--; p2--; if (*p != *p2) { x2 = (i << 3) + 7; @@ -2041,7 +2329,7 @@ static void update_display_static(driver } } else { - x1 = VideoMonitor.mode.x; + x1 = mode.x; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; @@ -2059,7 +2347,7 @@ static void update_display_static(driver p2 = &the_buffer_copy[j * bytes_per_row]; p += bytes_per_row; p2 += bytes_per_row; - for (i=VideoMonitor.mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) { + for (i=mode.x*bytes_per_pixel; i>x2*bytes_per_pixel; i--) { p--; p2--; if (*p != *p2) { @@ -2126,8 +2414,8 @@ static inline void handle_palette_change { LOCK_PALETTE; - if (palette_changed) { - palette_changed = false; + if (x_palette_changed) { + x_palette_changed = false; drv->update_palette(); } @@ -2138,12 +2426,6 @@ static void video_refresh_dga(void) { // Quit DGA mode if requested possibly_quit_dga_mode(); - - // Handle X events - handle_events(); - - // Handle palette changes - handle_palette_changes(); } #ifdef ENABLE_VOSF @@ -2153,12 +2435,6 @@ static void video_refresh_dga_vosf(void) // Quit DGA mode if requested possibly_quit_dga_mode(); - // Handle X events - handle_events(); - - // Handle palette changes - handle_palette_changes(); - // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { @@ -2177,12 +2453,6 @@ static void video_refresh_window_vosf(vo // Ungrab mouse if requested possibly_ungrab_mouse(); - // Handle X events - handle_events(); - - // Handle palette changes - handle_palette_changes(); - // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { @@ -2202,12 +2472,6 @@ static void video_refresh_window_static( // Ungrab mouse if requested possibly_ungrab_mouse(); - // Handle X events - handle_events(); - - // Handle_palette changes - handle_palette_changes(); - // Update display (static variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { @@ -2221,12 +2485,6 @@ static void video_refresh_window_dynamic // Ungrab mouse if requested possibly_ungrab_mouse(); - // Handle X events - handle_events(); - - // Handle_palette changes - handle_palette_changes(); - // Update display (dynamic variant) static int tick_counter = 0; tick_counter++; @@ -2262,32 +2520,69 @@ static void VideoRefreshInit(void) } } +// This function is called on non-threaded platforms from a timer interrupt void VideoRefresh(void) { // We need to check redraw_thread_active to inhibit refreshed during // mode changes on non-threaded platforms - if (redraw_thread_active) - video_refresh(); + if (!redraw_thread_active) + return; + + // Handle X events + handle_events(); + + // Handle palette changes + handle_palette_changes(); + + // Update display + video_refresh(); } +const int VIDEO_REFRESH_HZ = 60; +const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ; + #ifdef HAVE_PTHREADS static void *redraw_func(void *arg) { + int fd = ConnectionNumber(x_display); + uint64 start = GetTicks_usec(); int64 ticks = 0; - uint64 next = GetTicks_usec(); + uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY; + while (!redraw_thread_cancel) { - video_refresh(); - next += 16667; + int64 delay = next - GetTicks_usec(); - if (delay > 0) - Delay_usec(delay); - else if (delay < -16667) + if (delay < -VIDEO_REFRESH_DELAY) { + + // We are lagging far behind, so we reset the delay mechanism next = GetTicks_usec(); - ticks++; + + } else if (delay <= 0) { + + // Delay expired, refresh display + handle_events(); + handle_palette_changes(); + video_refresh(); + next += VIDEO_REFRESH_DELAY; + ticks++; + + } else { + + // No display refresh pending, check for X events + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = delay; + if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0) + handle_events(); + } } + uint64 end = GetTicks_usec(); - // printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start)); + D(bug("%Ld refreshes in %Ld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); return NULL; } #endif