--- BasiliskII/src/Unix/video_x.cpp 2001/07/06 20:49:53 1.53 +++ BasiliskII/src/Unix/video_x.cpp 2001/07/11 19:26:14 1.60 @@ -80,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; @@ -93,6 +93,7 @@ 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 @@ -183,7 +184,6 @@ 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; @@ -212,17 +212,13 @@ static bool find_visual_for_depth(video_ // Calculate minimum and maximum supported X depth int min_depth = 1, max_depth = 32; switch (depth) { - case VDEPTH_1BIT: // 1-bit works always - min_depth = 1; - max_depth = 32; + case VDEPTH_1BIT: // 1-bit works always and uses default visual + min_depth = max_depth = DefaultDepth(x_display, screen); break; #ifdef ENABLE_VOSF case VDEPTH_2BIT: - case VDEPTH_4BIT: // VOSF blitters can convert 2/4-bit -> 16/32-bit - min_depth = 15; - max_depth = 32; - break; - case VDEPTH_8BIT: // VOSF blitters can convert 8-bit -> 16/32-bit + 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; @@ -296,6 +292,7 @@ static bool find_visual_for_depth(video_ case DirectColor: D(bug("DirectColor\n")); break; } #endif + return true; } // Add mode to list of supported modes @@ -343,7 +340,6 @@ static void set_mac_frame_buffer(video_d InitFrameBufferMapping(); #else VideoMonitor.mac_frame_base = Host2MacAddr(the_buffer); - D(bug("Host frame buffer = %p, ", the_buffer)); #endif D(bug("VideoMonitor.mac_frame_base = %08x\n", VideoMonitor.mac_frame_base)); } @@ -432,12 +428,17 @@ 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: 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; @@ -481,11 +482,13 @@ driver_base::driver_base() { 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); @@ -509,12 +512,16 @@ driver_base::~driver_base() } #ifdef ENABLE_VOSF else { - if (the_buffer != (uint8 *)VM_MAP_FAILED) { - vm_release(the_buffer, the_buffer_size); + if (the_host_buffer) { + free(the_host_buffer); + the_host_buffer = NULL; + } + if (the_buffer) { + free(the_buffer); the_buffer = NULL; } - if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) { - vm_release(the_buffer_copy, the_buffer_size); + if (the_buffer_copy) { + free(the_buffer_copy); the_buffer_copy = NULL; } } @@ -524,11 +531,9 @@ 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 (color_class == DirectColor) + if (color_class == PseudoColor || color_class == DirectColor) { + int num = vis->map_entries; + if (!IsDirectMode(VideoMonitor.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); @@ -536,6 +541,18 @@ void driver_base::update_palette(void) 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 @@ -543,7 +560,7 @@ void driver_base::update_palette(void) // Open display driver_window::driver_window(const video_mode &mode) - : gc(0), img(NULL), have_shm(false), mouse_grabbed(false), mac_cursor(0) + : 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; @@ -552,13 +569,16 @@ driver_window::driver_window(const video // Set absolute mouse mode ADBSetRelMouseMode(mouse_grabbed); - // Create window + // Create window (setting backround_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 && color_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 | (color_class == PseudoColor || color_class == DirectColor ? CWColormap : 0), &wattr); + InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); @@ -610,6 +630,7 @@ driver_window::driver_window(const video if (shm_error) { shmdt(shminfo.shmaddr); XDestroyImage(img); + img = NULL; shminfo.shmid = -1; } else { have_shm = true; @@ -630,14 +651,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); + 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 @@ -673,11 +697,32 @@ 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 + } +#ifdef ENABLE_VOSF + if (use_vosf) { + // don't free() memory mapped buffers in driver_base dtor + if (the_buffer != VM_MAP_FAILED) { + vm_release(the_buffer, the_buffer_size); + the_buffer = NULL; + } + if (the_buffer_copy != VM_MAP_FAILED) { + vm_release(the_buffer_copy, the_buffer_size); + the_buffer_copy = NULL; + } + } +#endif + if (img) + XDestroyImage(img); + if (have_shm) { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); } if (gc) XFreeGC(x_display, gc); @@ -704,9 +749,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(); } } @@ -717,6 +762,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(); } } @@ -812,6 +858,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); @@ -841,6 +888,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); @@ -987,13 +1035,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); @@ -1032,6 +1082,30 @@ 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; + } + if (the_buffer_copy != VM_MAP_FAILED) { + vm_release(the_buffer_copy, the_buffer_size); + the_buffer_copy = NULL; + } + if (the_buffer != VM_MAP_FAILED) { + vm_release(the_buffer, the_buffer_size); + the_buffer = NULL; + } + } +#endif } #endif @@ -1101,6 +1175,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); @@ -1117,7 +1192,7 @@ driver_xf86dga::driver_xf86dga(const vid // Init blitting routines int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth); -#ifdef VIDEO_VOSF +#if VIDEO_VOSF #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 @@ -1148,6 +1223,25 @@ 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; + + if (the_buffer_copy != VM_MAP_FAILED) { + vm_release(the_buffer_copy, the_buffer_size); + the_buffer_copy = NULL; + } + if (the_buffer != VM_MAP_FAILED) { + vm_release(the_buffer, the_buffer_size); + the_buffer = NULL; + } + } +#endif #ifdef ENABLE_XF86_VIDMODE if (has_vidmode) XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]); @@ -1255,6 +1349,9 @@ static bool video_open(const video_mode 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 @@ -1276,12 +1373,18 @@ static bool video_open(const video_mode --bloss; } - // Preset palette pixel values for gamma table + // Preset palette pixel values for CLUT or gamma table if (color_class == DirectColor) { int num = vis->map_entries; for (int i=0; i16/32 expand map - if (!IsDirectMode(mode) && (color_class == TrueColor || color_class == DirectColor)) + if (!IsDirectMode(mode) && xdepth > 8) for (int i=0; i<256; i++) ExpandMap[i] = map_rgb(i, i, i); #endif @@ -1334,17 +1434,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()) { 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 @@ -1560,16 +1654,9 @@ static void video_close(void) XSync(x_display, false); #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 @@ -1655,25 +1742,24 @@ void video_set_palette(uint8 *pal, int n // Convert colors to XColor array int num_out = 256; + bool stretch = false; if (IsDirectMode(VideoMonitor.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; 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 (color_class == PseudoColor) - p->pixel = i; - p->flags = DoRed | DoGreen | DoBlue; p++; } #ifdef ENABLE_VOSF // Recalculate pixel color expansion map - if (!IsDirectMode(VideoMonitor.mode) && (color_class == TrueColor || color_class == DirectColor)) { + if (!IsDirectMode(VideoMonitor.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]); @@ -1886,6 +1972,7 @@ static void handle_events(void) XNextEvent(x_display, &event); switch (event.type) { + // Mouse button case ButtonPress: { unsigned int button = event.xbutton.button; @@ -1918,6 +2005,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; @@ -2095,7 +2188,7 @@ 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; + unsigned 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; uint8 *p, *p2; @@ -2254,12 +2347,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 @@ -2269,12 +2356,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) { @@ -2293,12 +2374,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) { @@ -2318,12 +2393,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) { @@ -2337,12 +2406,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++; @@ -2378,32 +2441,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