--- BasiliskII/src/Unix/video_x.cpp 2001/07/03 19:20:46 1.52 +++ BasiliskII/src/Unix/video_x.cpp 2001/07/10 15:50:57 1.58 @@ -37,6 +37,12 @@ #include #include +#include + +#ifndef NO_STD_NAMESPACE +using std::sort; +#endif + #ifdef HAVE_PTHREADS # include #endif @@ -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,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 @@ -116,17 +123,22 @@ static int keycode_table[256]; // X // X11 variables 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 XVisualInfo visualInfo; +static Visual *vis; +static int color_class; + static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes +static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) + 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 @@ -192,6 +204,97 @@ static inline uint32 map_rgb(uint8 red, 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)); + + // Calculate minimum and maximum supported X depth + int min_depth = 1, max_depth = 32; + switch (depth) { + 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/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 +} + // 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) { @@ -237,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)); } @@ -326,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; @@ -375,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); @@ -403,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; } } @@ -418,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 (vis->c_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); @@ -430,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 @@ -446,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 && 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); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); @@ -504,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; @@ -524,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 @@ -567,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); @@ -598,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(); } } @@ -611,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(); } } @@ -706,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); @@ -735,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); @@ -881,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); @@ -926,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 @@ -995,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); @@ -1011,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 @@ -1042,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]); @@ -1139,25 +1339,71 @@ static void keycode_init(void) // Open display for specified mode static bool video_open(const video_mode &mode) { + // Find best available X visual + if (!find_visual_for_depth(mode.depth)) { + ErrorAlert(STR_NO_XVISUAL_ERR); + return false; + } + + // 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]) { + if (color_class == PseudoColor || color_class == DirectColor) { XStoreColors(x_display, cmap[0], palette, num); XStoreColors(x_display, cmap[1], 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 @@ -1188,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 @@ -1249,9 +1489,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; + } + sort(avail_depths, avail_depths + num_depths); #ifdef ENABLE_FBDEV_DGA // Frame buffer name @@ -1291,71 +1536,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; + } video_init_depth_list(); +#if DEBUG + D(bug("Available video modes:\n")); + vector::const_iterator i = VideoModes.begin(), end = VideoModes.end(); + while (i != end) { + 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)); + ++i; + } +#endif + // Find requested default mode and open display if (VideoModes.size() == 1) return video_open(VideoModes[0]); @@ -1451,28 +1654,15 @@ 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 // Close display delete drv; drv = NULL; -} - -void VideoExit(void) -{ - // Close display - video_close(); // Free colormaps if (cmap[0]) { @@ -1483,6 +1673,12 @@ void VideoExit(void) XFreeColormap(x_display, cmap[1]); cmap[1] = 0; } +} + +void VideoExit(void) +{ + // Close display + video_close(); #ifdef ENABLE_XF86_VIDMODE // Free video mode list @@ -1499,6 +1695,12 @@ void VideoExit(void) fbdev_fd = -1; } #endif + + // Free depth list + if (avail_depths) { + XFree(avail_depths); + avail_depths = NULL; + } } @@ -1540,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 (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(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]); @@ -1771,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; @@ -1803,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; @@ -2139,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 @@ -2154,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) { @@ -2178,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) { @@ -2203,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) { @@ -2222,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++; @@ -2263,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