--- SheepShaver/src/Unix/video_x.cpp 2004/04/18 23:17:54 1.17 +++ SheepShaver/src/Unix/video_x.cpp 2004/12/18 18:34:56 1.34 @@ -46,6 +46,7 @@ #include "about_window.h" #include "video.h" #include "video_defs.h" +#include "video_blit.h" #define DEBUG 0 #include "debug.h" @@ -57,6 +58,7 @@ using std::sort; // Constants const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; +static const bool hw_mac_cursor_accl = true; // Flag: Enable MacOS to X11 copy of cursor? // Global variables static int32 frame_skip; @@ -64,6 +66,7 @@ static int16 mouse_wheel_mode; static int16 mouse_wheel_lines; static bool redraw_thread_active = false; // Flag: Redraw thread installed 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 static bool local_X11; // Flag: X server running on local machine? @@ -81,6 +84,7 @@ static const bool use_vosf = false; // static bool palette_changed = false; // Flag: Palette changed, redraw thread must update palette static bool ctrl_down = false; // Flag: Ctrl key pressed +static bool caps_on = false; // Flag: Caps Lock on static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread static volatile bool quit_full_screen_ack = false; // Acknowledge for quit_full_screen static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread @@ -98,6 +102,7 @@ static int depth; // Depth of Mac static Window rootwin, the_win; // Root window and our window static int num_depths = 0; // Number of available X depths static int *avail_depths = NULL; // List of available X depths +static VisualFormat visualFormat; static XVisualInfo visualInfo; static Visual *vis; static int color_class; @@ -498,25 +503,36 @@ static bool open_window(int width, int h 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 - screen_base = (uint32)the_buffer; + screen_base = Host2MacAddr(the_buffer); // Create GC the_gc = XCreateGC(x_display, the_win, 0, 0); XSetState(x_display, the_gc, black_pixel, white_pixel, GXcopy, AllPlanes); // Create cursor - cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 4, 16, 16, 16, 2); - cursor_image->byte_order = MSBFirst; - cursor_image->bitmap_bit_order = MSBFirst; - cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 36, 16, 16, 16, 2); - cursor_mask_image->byte_order = MSBFirst; - cursor_mask_image->bitmap_bit_order = MSBFirst; - cursor_map = XCreatePixmap(x_display, the_win, 16, 16, 1); - cursor_mask_map = XCreatePixmap(x_display, the_win, 16, 16, 1); - cursor_gc = XCreateGC(x_display, cursor_map, 0, 0); - cursor_mask_gc = XCreateGC(x_display, cursor_mask_map, 0, 0); - mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0); - cursor_changed = false; + if (hw_mac_cursor_accl) { + cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 4, 16, 16, 16, 2); + cursor_image->byte_order = MSBFirst; + cursor_image->bitmap_bit_order = MSBFirst; + cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 36, 16, 16, 16, 2); + cursor_mask_image->byte_order = MSBFirst; + cursor_mask_image->bitmap_bit_order = MSBFirst; + cursor_map = XCreatePixmap(x_display, the_win, 16, 16, 1); + cursor_mask_map = XCreatePixmap(x_display, the_win, 16, 16, 1); + cursor_gc = XCreateGC(x_display, cursor_map, 0, 0); + cursor_mask_gc = XCreateGC(x_display, cursor_mask_map, 0, 0); + mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0); + cursor_changed = false; + } + + // Create no_cursor + else { + mac_cursor = XCreatePixmapCursor(x_display, + XCreatePixmap(x_display, the_win, 1, 1, 1), + XCreatePixmap(x_display, the_win, 1, 1, 1), + &black, &white, 0, 0); + XDefineCursor(x_display, the_win, mac_cursor); + } // Init blitting routines bool native_byte_order; @@ -526,7 +542,7 @@ static bool open_window(int width, int h native_byte_order = (XImageByteOrder(x_display) == LSBFirst); #endif #ifdef ENABLE_VOSF - Screen_blitter_init(&visualInfo, native_byte_order, depth); + Screen_blitter_init(visualFormat, native_byte_order, depth); #endif // Set bytes per row @@ -600,7 +616,7 @@ static bool open_dga(int width, int heig #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, native_byte_order, depth); + use_vosf = Screen_blitter_init(visualFormat, native_byte_order, depth); if (use_vosf) { // Allocate memory for frame buffer (SIZE is extended to page-boundary) @@ -617,7 +633,7 @@ static bool open_dga(int width, int heig // Set frame buffer base D(bug("the_buffer = %p, use_vosf = %d\n", the_buffer, use_vosf)); - screen_base = (uint32)the_buffer; + screen_base = Host2MacAddr(the_buffer); VModes[cur_mode].viRowBytes = bytes_per_row; return true; #else @@ -637,6 +653,12 @@ static bool open_display(void) 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); @@ -870,6 +892,10 @@ static void keycode_init(void) // Search for server vendor string, then read keycodes const char *vendor = ServerVendor(x_display); + // Force use of MacX mappings on MacOS X with Apple's X server + int dummy; + if (XQueryExtension(x_display, "Apple-DRI", &dummy, &dummy, &dummy)) + vendor = "MacX"; bool vendor_found = false; char line[256]; while (fgets(line, 255, f)) { @@ -1149,8 +1175,15 @@ bool VideoInit(void) if (apple_id != -1) cur_mode = find_mode(default_mode, apple_id, DIS_SCREEN); } - if (cur_mode == -1) - cur_mode = find_mode(default_mode, APPLE_W_640x480, DIS_WINDOW); + if (cur_mode == -1) { + // pick up first windowed mode available + for (VideoInfo *p = VModes; p->viType != DIS_INVALID; p++) { + if (p->viType == DIS_WINDOW && p->viAppleMode == default_mode) { + cur_mode = p - VModes; + break; + } + } + } assert(cur_mode != -1); #if DEBUG @@ -1173,6 +1206,7 @@ bool VideoInit(void) // Start periodic thread XSync(x_display, false); Set_pthread_attr(&redraw_thread_attr, 0); + redraw_thread_cancel = false; redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0); D(bug("Redraw thread installed (%ld)\n", redraw_thread)); return true; @@ -1187,6 +1221,7 @@ void VideoExit(void) { // Stop redraw thread if (redraw_thread_active) { + redraw_thread_cancel = true; pthread_cancel(redraw_thread); pthread_join(redraw_thread, NULL); redraw_thread_active = false; @@ -1230,7 +1265,7 @@ static void suspend_emul(void) // Save frame buffer fb_save = malloc(VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); if (fb_save) - memcpy(fb_save, (void *)screen_base, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); + Mac2Host_memcpy(fb_save, screen_base, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); // Close full screen display #ifdef ENABLE_XF86_DGA @@ -1292,7 +1327,7 @@ static void resume_emul(void) // Don't copy fb_save to the temporary frame buffer in VOSF mode if (!use_vosf) #endif - memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); + Host2Mac_memcpy(screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); free(fb_save); fb_save = NULL; } @@ -1465,16 +1500,17 @@ static int kc_decode(KeySym ks) return -1; } -static int event2keycode(XKeyEvent &ev) +static int event2keycode(XKeyEvent &ev, bool key_down) { KeySym ks; - int as; int i = 0; do { ks = XLookupKeysym(&ev, i++); - as = kc_decode(ks); - if (as != -1) + int as = kc_decode(ks); + if (as >= 0) + return as; + if (as == -2) return as; } while (ks != NoSymbol); @@ -1549,12 +1585,24 @@ static void handle_events(void) // Keyboard case KeyPress: { - int code = event2keycode(event.xkey); - if (use_keycodes && code != -1) - code = keycode_table[event.xkey.keycode & 0xff]; - if (code != -1) { + int code = -1; + if (use_keycodes) { + if (event2keycode(event.xkey, true) != -2) // This is called to process the hotkeys + code = keycode_table[event.xkey.keycode & 0xff]; + } else + code = event2keycode(event.xkey, true); + if (code >= 0) { if (!emul_suspended) { - ADBKeyDown(code); + if (code == 0x39) { // Caps Lock pressed + if (caps_on) { + ADBKeyUp(code); + caps_on = false; + } else { + ADBKeyDown(code); + caps_on = true; + } + } else + ADBKeyDown(code); if (code == 0x36) ctrl_down = true; } else { @@ -1565,10 +1613,13 @@ static void handle_events(void) break; } case KeyRelease: { - int code = event2keycode(event.xkey); - if (use_keycodes && code != 1) - code = keycode_table[event.xkey.keycode & 0xff]; - if (code != -1) { + int code = -1; + if (use_keycodes) { + if (event2keycode(event.xkey, false) != -2) // This is called to process the hotkeys + code = keycode_table[event.xkey.keycode & 0xff]; + } else + code = event2keycode(event.xkey, false); + if (code >= 0 && code != 0x39) { // Don't propagate Caps Lock releases ADBKeyUp(code); if (code == 0x36) ctrl_down = false; @@ -1608,184 +1659,6 @@ void VideoVBL(void) /* - * Install graphics acceleration - */ - -#if 0 -// Rectangle filling/inversion -static void accl_fillrect8(accl_params *p) -{ - D(bug("accl_fillrect8\n")); - - // Get filling parameters - int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; - int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; - int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; - int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; - uint8 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; - D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); - D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); - - // And perform the fill - fillrect8_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); -} - -static void accl_fillrect32(accl_params *p) -{ - D(bug("accl_fillrect32\n")); - - // Get filling parameters - int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; - int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; - int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; - int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; - uint32 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; - D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); - D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); - - // And perform the fill - fillrect32_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); -} - -static void accl_invrect(accl_params *p) -{ - D(bug("accl_invrect\n")); - - // Get inversion parameters - int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; - int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; - int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; - int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; - D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); - D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); - - //!!?? pen_mode == 14 - - // And perform the inversion - invrect_hook(dest_X, dest_Y, dest_X_max, dest_Y_max); -} - -static bool accl_fillrect_hook(accl_params *p) -{ - D(bug("accl_fillrect_hook %p\n", p)); - - // Check if we can accelerate this fillrect - if (p->dest_base_addr == screen_base && ((uint32 *)p)[0x284 >> 2] != 0 && display_type == DIS_SCREEN) { - if (p->transfer_mode == 8) { - // Fill - if (p->dest_pixel_size == 8 && fillrect8_hook != NULL) { - p->draw_proc = accl_fillrect8; - return true; - } else if (p->dest_pixel_size == 32 && fillrect32_hook != NULL) { - p->draw_proc = accl_fillrect32; - return true; - } - } else if (p->transfer_mode == 10 && invrect_hook != NULL) { - // Invert - p->draw_proc = accl_invrect; - return true; - } - } - return false; -} - -static struct accl_hook_info fillrect_hook_info = {accl_fillrect_hook, accl_sync_hook, ACCL_FILLRECT}; -#endif - -// Rectangle blitting -// TODO: optimize for VOSF and target pixmap == screen -void NQD_bitblt(uint32 arg) -{ - D(bug("accl_bitblt %08x\n", arg)); - accl_params *p = (accl_params *)arg; - - // Get blitting parameters - int16 src_X = p->src_rect[1] - p->src_bounds[1]; - int16 src_Y = p->src_rect[0] - p->src_bounds[0]; - int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; - int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; - int16 width = p->dest_rect[3] - p->dest_rect[1]; - int16 height = p->dest_rect[2] - p->dest_rect[0]; - D(bug(" src addr %08x, dest addr %08x\n", p->src_base_addr, p->dest_base_addr)); - D(bug(" src X %d, src Y %d, dest X %d, dest Y %d\n", src_X, src_Y, dest_X, dest_Y)); - D(bug(" width %d, height %d\n", width, height)); - - // And perform the blit - const int bpp = bytes_per_pixel(p->src_pixel_size); - width *= bpp; - if (p->src_row_bytes > 0) { - const int src_row_bytes = p->src_row_bytes; - const int dst_row_bytes = p->dest_row_bytes; - uint8 *src = (uint8 *)p->src_base_addr + (src_Y * src_row_bytes) + (src_X * bpp); - uint8 *dst = (uint8 *)p->dest_base_addr + (dest_Y * dst_row_bytes) + (dest_X * bpp); - for (int i = 0; i < height; i++) { - memcpy(dst, src, width); - src += src_row_bytes; - dst += dst_row_bytes; - } - } - else { - const int src_row_bytes = -p->src_row_bytes; - const int dst_row_bytes = -p->dest_row_bytes; - uint8 *src = (uint8 *)p->src_base_addr + ((src_Y + height - 1) * src_row_bytes) + (src_X * bpp); - uint8 *dst = (uint8 *)p->dest_base_addr + ((dest_Y + height - 1) * dst_row_bytes) + (dest_X * bpp); - for (int i = height - 1; i >= 0; i--) { - memcpy(dst, src, width); - src -= src_row_bytes; - dst -= dst_row_bytes; - } - } -} - -bool NQD_bitblt_hook(uint32 arg) -{ - D(bug("accl_draw_hook %08x\n", arg)); - accl_params *p = (accl_params *)arg; - - // Check if we can accelerate this bitblt - if (((uint32 *)p)[0x18 >> 2] + ((uint32 *)p)[0x128 >> 2] == 0 && - ((uint32 *)p)[0x130 >> 2] == 0 && - p->src_pixel_size >= 8 && p->src_pixel_size == p->dest_pixel_size && - ((p->src_row_bytes ^ p->dest_row_bytes) >> 31) == 0 && - p->transfer_mode == 0 && - ((uint32 *)p)[0x15c >> 2] > 0) { - - // Yes, set function pointer - p->draw_proc = NativeTVECT(NATIVE_BITBLT); - return true; - } - return false; -} - -// Wait for graphics operation to finish -bool NQD_sync_hook(uint32 arg) -{ - D(bug("accl_sync_hook %08x\n", arg)); - return true; -} - -void VideoInstallAccel(void) -{ - // Install acceleration hooks - if (PrefsFindBool("gfxaccel")) { - D(bug("Video: Installing acceleration hooks\n")); - uint32 base; - - SheepVar bitblt_hook_info(sizeof(accl_hook_info)); - base = bitblt_hook_info.addr(); - WriteMacInt32(base + 0, NativeTVECT(NATIVE_BITBLT_HOOK)); - WriteMacInt32(base + 4, NativeTVECT(NATIVE_SYNC_HOOK)); - WriteMacInt32(base + 8, ACCL_BITBLT); -#if defined(__powerpc__) // Temporary hack until it's fixed for e.g. little-endian & 64-bit platforms - NQDMisc(6, bitblt_hook_info.ptr()); -#endif - -// NQDMisc(6, &fillrect_hook_info); - } -} - - -/* * Change video mode */ @@ -1888,6 +1761,16 @@ void video_set_palette(void) /* + * Can we set the MacOS cursor image into the window? + */ + +bool video_can_change_cursor(void) +{ + return hw_mac_cursor_accl && (display_type != DIS_SCREEN); +} + + +/* * Set cursor image for window */ @@ -2067,7 +1950,7 @@ static void *redraw_func(void *arg) int64 ticks = 0; uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY; - for (;;) { + while (!redraw_thread_cancel) { // Pause if requested (during video mode switches) while (thread_stop_req) @@ -2132,10 +2015,14 @@ static void *redraw_func(void *arg) update_display(); // Set new cursor image if it was changed - if (cursor_changed) { + if (hw_mac_cursor_accl && cursor_changed) { cursor_changed = false; - memcpy(cursor_image->data, MacCursor + 4, 32); - memcpy(cursor_mask_image->data, MacCursor + 36, 32); + uint8 *x_data = (uint8 *)cursor_image->data; + uint8 *x_mask = (uint8 *)cursor_mask_image->data; + for (int i = 0; i < 32; i++) { + x_mask[i] = MacCursor[4 + i] | MacCursor[36 + i]; + x_data[i] = MacCursor[4 + i]; + } XDisplayLock(); XFreeCursor(x_display, mac_cursor); XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16);