--- SheepShaver/src/Unix/video_x.cpp 2004/04/11 10:46:32 1.14 +++ SheepShaver/src/Unix/video_x.cpp 2004/05/16 15:48:25 1.23 @@ -32,7 +32,7 @@ #include #ifdef ENABLE_XF86_DGA -#include +# include #endif #ifdef ENABLE_XF86_VIDMODE @@ -57,12 +57,14 @@ 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; 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 pthread_t redraw_thread; // Redraw thread static bool local_X11; // Flag: X server running on local machine? @@ -125,8 +127,6 @@ static uint8 *the_buffer_copy = NULL; / static uint32 the_buffer_size; // Size of allocated the_buffer // Variables for DGA mode -static char *dga_screen_base; -static int dga_fb_width; static int current_dga_cmap; #ifdef ENABLE_XF86_VIDMODE @@ -196,10 +196,30 @@ static int palette_size(int mode) } } +// Return bits per pixel for requested depth +static inline int bytes_per_pixel(int depth) +{ + int bpp; + switch (depth) { + case 8: + bpp = 1; + break; + case 15: case 16: + bpp = 2; + break; + case 24: case 32: + bpp = 4; + break; + default: + abort(); + } + return bpp; +} + // Map video_mode depth ID to numerical depth value static inline int depth_of_video_mode(int mode) { - int depth = -1; + int depth; switch (mode) { case APPLE_1_BIT: depth = 1; @@ -349,7 +369,7 @@ static void set_window_delete_protocol(W } // Wait until window is mapped/unmapped -void wait_mapped(Window w) +static void wait_mapped(Window w) { XEvent e; do { @@ -357,7 +377,7 @@ void wait_mapped(Window w) } while ((e.type != MapNotify) || (e.xmap.event != w)); } -void wait_unmapped(Window w) +static void wait_unmapped(Window w) { XEvent e; do { @@ -486,18 +506,29 @@ static bool open_window(int width, int h 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; @@ -522,6 +553,19 @@ static bool open_dga(int width, int heig // Set relative mouse mode ADBSetRelMouseMode(true); + // Create window + XSetWindowAttributes wattr; + wattr.event_mask = eventmask = dga_eventmask; + wattr.override_redirect = True; + wattr.colormap = (depth == 1 ? DefaultColormap(x_display, screen) : cmap[0]); + the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, + InputOutput, vis, CWEventMask | CWOverrideRedirect | + (color_class == DirectColor ? CWColormap : 0), &wattr); + + // Show window + XMapRaised(x_display, the_win); + wait_mapped(the_win); + #ifdef ENABLE_XF86_VIDMODE // Switch to best mode if (has_vidmode) { @@ -538,19 +582,26 @@ static bool open_dga(int width, int heig #endif // Establish direct screen connection + XMoveResizeWindow(x_display, the_win, 0, 0, width, height); + 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); + + int v_width, v_bank, v_size; + XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size); XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); XF86DGASetViewPort(x_display, screen, 0, 0); XF86DGASetVidPage(x_display, screen, 0); // Set colormap - if (depth == 8) + if (!IsDirectMode(get_current_mode())) { + XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]); XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); + } + XSync(x_display, false); - // Set bytes per row - int bytes_per_row = TrivialBytesPerRow((dga_fb_width + 7) & ~7, DepthModeForPixelDepth(depth)); - + // Init blitting routines + int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, DepthModeForPixelDepth(depth)); #if ENABLE_VOSF bool native_byte_order; #ifdef WORDS_BIGENDIAN @@ -569,16 +620,17 @@ static bool open_dga(int width, int heig the_buffer_size = page_extend((height + 2) * bytes_per_row); the_buffer_copy = (uint8 *)malloc(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 use_vosf = false; - the_buffer = dga_screen_base; #endif #endif - screen_base = (uint32)the_buffer; + // Set frame buffer base + D(bug("the_buffer = %p, use_vosf = %d\n", the_buffer, use_vosf)); + screen_base = (uint32)the_buffer; VModes[cur_mode].viRowBytes = bytes_per_row; - XSync(x_display, false); return true; #else ErrorAlert("SheepShaver has been compiled with DGA support disabled."); @@ -711,13 +763,6 @@ static void close_window(void) if (the_gc) XFreeGC(x_display, the_gc); - // Close window - if (the_win) { - XUnmapWindow(x_display, the_win); - wait_unmapped(the_win); - XDestroyWindow(x_display, the_win); - } - XFlush(x_display); XSync(x_display, false); } @@ -755,6 +800,13 @@ static void close_display(void) else if (display_type == DIS_WINDOW) close_window(); + // Close window + if (the_win) { + XUnmapWindow(x_display, the_win); + wait_unmapped(the_win); + XDestroyWindow(x_display, the_win); + } + // Free colormaps if (cmap[0]) { XFreeColormap(x_display, cmap[0]); @@ -871,6 +923,39 @@ static void keycode_init(void) } } +// Find Apple mode matching best specified dimensions +static int find_apple_resolution(int xsize, int ysize) +{ + int apple_id; + if (xsize < 800) + apple_id = APPLE_640x480; + else if (xsize < 1024) + apple_id = APPLE_800x600; + else if (xsize < 1152) + apple_id = APPLE_1024x768; + else if (xsize < 1280) { + if (ysize < 900) + apple_id = APPLE_1152x768; + else + apple_id = APPLE_1152x900; + } + else if (xsize < 1600) + apple_id = APPLE_1280x1024; + else + apple_id = APPLE_1600x1200; + return apple_id; +} + +// Find mode in list of supported modes +static int find_mode(int apple_mode, int apple_id, int type) +{ + for (VideoInfo *p = VModes; p->viType != DIS_INVALID; p++) { + if (p->viType == type && p->viAppleID == apple_id && p->viAppleMode == apple_mode) + return p - VModes; + } + return -1; +} + // Add mode to list of supported modes static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, int apple_mode, int apple_id, int type) { @@ -891,6 +976,10 @@ static void add_mode(VideoInfo *&p, uint p->viXsize = 1024; p->viYsize = 768; break; + case APPLE_1152x768: + p->viXsize = 1152; + p->viYsize = 768; + break; case APPLE_1152x900: p->viXsize = 1152; p->viYsize = 900; @@ -1037,6 +1126,8 @@ bool VideoInit(void) add_mode(p, screen_modes, 2, default_mode, APPLE_800x600, DIS_SCREEN); if (has_mode(1024, 768)) add_mode(p, screen_modes, 4, default_mode, APPLE_1024x768, DIS_SCREEN); + if (has_mode(1152, 768)) + add_mode(p, screen_modes, 64, default_mode, APPLE_1152x768, DIS_SCREEN); if (has_mode(1152, 900)) add_mode(p, screen_modes, 8, default_mode, APPLE_1152x900, DIS_SCREEN); if (has_mode(1280, 1024)) @@ -1046,19 +1137,7 @@ bool VideoInit(void) } else if (screen_modes) { int xsize = DisplayWidth(x_display, screen); int ysize = DisplayHeight(x_display, screen); - int apple_id; - if (xsize < 800) - apple_id = APPLE_640x480; - else if (xsize < 1024) - apple_id = APPLE_800x600; - else if (xsize < 1152) - apple_id = APPLE_1024x768; - else if (xsize < 1280) - apple_id = APPLE_1152x900; - else if (xsize < 1600) - apple_id = APPLE_1280x1024; - else - apple_id = APPLE_1600x1200; + int apple_id = find_apple_resolution(xsize, ysize); p->viType = DIS_SCREEN; p->viRowBytes = 0; p->viXsize = xsize; @@ -1075,14 +1154,15 @@ bool VideoInit(void) // Find default mode (window 640x480) cur_mode = -1; - for (p = VModes; p->viType != DIS_INVALID; p++) { - if (p->viType == DIS_WINDOW - && p->viAppleID == APPLE_W_640x480 - && p->viAppleMode == default_mode) { - cur_mode = p - VModes; - break; - } + if (has_dga && screen_modes) { + int screen_width = DisplayWidth(x_display, screen); + int screen_height = DisplayHeight(x_display, screen); + int apple_id = find_apple_resolution(screen_width, screen_height); + 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); assert(cur_mode != -1); #if DEBUG @@ -1093,14 +1173,6 @@ bool VideoInit(void) } #endif -#ifdef ENABLE_XF86_DGA - if (has_dga && screen_modes) { - int v_bank, v_size; - XF86DGAGetVideo(x_display, screen, &dga_screen_base, &dga_fb_width, &v_bank, &v_size); - D(bug("DGA screen_base %p, v_width %d\n", dga_screen_base, dga_fb_width)); - } -#endif - // Open window/screen if (!open_display()) return false; @@ -1112,7 +1184,8 @@ bool VideoInit(void) // Start periodic thread XSync(x_display, 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); D(bug("Redraw thread installed (%ld)\n", redraw_thread)); return true; } @@ -1475,12 +1548,15 @@ static void handle_events(void) break; } - // Mouse moved + // Mouse entered window case EnterNotify: - ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y); + if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab) + ADBMouseMoved(event.xmotion.x, event.xmotion.y); break; + + // Mouse moved case MotionNotify: - ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y); + ADBMouseMoved(event.xmotion.x, event.xmotion.y); break; // Keyboard @@ -1547,142 +1623,363 @@ void VideoVBL(void) * Install graphics acceleration */ -#if 0 -// Rectangle blitting -static void accl_bitblt(accl_params *p) +// Rectangle inversion +template< int bpp > +static inline void do_invrect(uint8 *dest, uint32 length) { - D(bug("accl_bitblt\n")); +#define INVERT_1(PTR, OFS) ((uint8 *)(PTR))[OFS] = ~((uint8 *)(PTR))[OFS] +#define INVERT_2(PTR, OFS) ((uint16 *)(PTR))[OFS] = ~((uint16 *)(PTR))[OFS] +#define INVERT_4(PTR, OFS) ((uint32 *)(PTR))[OFS] = ~((uint32 *)(PTR))[OFS] +#define INVERT_8(PTR, OFS) ((uint64 *)(PTR))[OFS] = ~((uint64 *)(PTR))[OFS] - // 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] - 1; - int16 height = p->dest_rect[2] - p->dest_rect[0] - 1; - 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)); +#ifndef UNALIGNED_PROFITABLE + // Align on 16-bit boundaries + if (bpp < 16 && (((uintptr)dest) & 1)) { + INVERT_1(dest, 0); + dest += 1; length -= 1; + } - // And perform the blit - bitblt_hook(src_X, src_Y, dest_X, dest_Y, width, height); -} + // Align on 32-bit boundaries + if (bpp < 32 && (((uintptr)dest) & 2)) { + INVERT_2(dest, 0); + dest += 2; length -= 2; + } +#endif -static bool accl_bitblt_hook(accl_params *p) -{ - D(bug("accl_draw_hook %p\n", p)); + // Invert 8-byte words + if (length >= 8) { + const int r = (length / 8) % 8; + dest += r * 8; - // Check if we can accelerate this bitblt - if (p->src_base_addr == screen_base && p->dest_base_addr == screen_base && - display_type == DIS_SCREEN && bitblt_hook != NULL && - ((uint32 *)p)[0x18 >> 2] + ((uint32 *)p)[0x128 >> 2] == 0 && - ((uint32 *)p)[0x130 >> 2] == 0 && - p->transfer_mode == 0 && - p->src_row_bytes > 0 && ((uint32 *)p)[0x15c >> 2] > 0) { + int n = ((length / 8) + 7) / 8; + switch (r) { + case 0: do { + dest += 64; + INVERT_8(dest, -8); + case 7: INVERT_8(dest, -7); + case 6: INVERT_8(dest, -6); + case 5: INVERT_8(dest, -5); + case 4: INVERT_8(dest, -4); + case 3: INVERT_8(dest, -3); + case 2: INVERT_8(dest, -2); + case 1: INVERT_8(dest, -1); + } while (--n > 0); + } + } - // Yes, set function pointer - p->draw_proc = accl_bitblt; - return true; + // 32-bit cell to invert? + if (length & 4) { + INVERT_4(dest, 0); + if (bpp <= 16) + dest += 4; } - return false; + + // 16-bit cell to invert? + if (bpp <= 16 && (length & 2)) { + INVERT_2(dest, 0); + if (bpp <= 8) + dest += 2; + } + + // 8-bit cell to invert? + if (bpp <= 8 && (length & 1)) + INVERT_1(dest, 0); + +#undef INVERT_1 +#undef INVERT_2 +#undef INVERT_4 +#undef INVERT_8 } -// Rectangle filling/inversion -static void accl_fillrect8(accl_params *p) +void NQD_invrect(uint32 p) { - D(bug("accl_fillrect8\n")); + D(bug("accl_invrect %08x\n", p)); - // 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; + // Get inversion parameters + int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); + int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); + int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); + int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); 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)); + D(bug(" width %d, height %d, bytes_per_row %d\n", width, height, (int32)ReadMacInt32(p + acclDestRowBytes))); - // And perform the fill - fillrect8_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); + //!!?? pen_mode == 14 + + // And perform the inversion + const int bpp = bytes_per_pixel(ReadMacInt32(p + acclDestPixelSize)); + const int dest_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); + uint8 *dest = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dest_row_bytes) + (dest_X * bpp)); + width *= bpp; + switch (bpp) { + case 1: + for (int i = 0; i < height; i++) { + do_invrect<8>(dest, width); + dest += dest_row_bytes; + } + break; + case 2: + for (int i = 0; i < height; i++) { + do_invrect<16>(dest, width); + dest += dest_row_bytes; + } + break; + case 4: + for (int i = 0; i < height; i++) { + do_invrect<32>(dest, width); + dest += dest_row_bytes; + } + break; + } } -static void accl_fillrect32(accl_params *p) +// Rectangle filling +template< int bpp > +static inline void do_fillrect(uint8 *dest, uint32 color, uint32 length) { - D(bug("accl_fillrect32\n")); +#define FILL_1(PTR, OFS, VAL) ((uint8 *)(PTR))[OFS] = (VAL) +#define FILL_2(PTR, OFS, VAL) ((uint16 *)(PTR))[OFS] = (VAL) +#define FILL_4(PTR, OFS, VAL) ((uint32 *)(PTR))[OFS] = (VAL) +#define FILL_8(PTR, OFS, VAL) ((uint64 *)(PTR))[OFS] = (VAL) - // 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)); +#ifndef UNALIGNED_PROFITABLE + // Align on 16-bit boundaries + if (bpp < 16 && (((uintptr)dest) & 1)) { + FILL_1(dest, 0, color); + dest += 1; length -= 1; + } - // And perform the fill - fillrect32_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); + // Align on 32-bit boundaries + if (bpp < 32 && (((uintptr)dest) & 2)) { + FILL_2(dest, 0, color); + dest += 2; length -= 2; + } +#endif + + // Fill 8-byte words + if (length >= 8) { + const uint64 c = (((uint64)color) << 32) | color; + const int r = (length / 8) % 8; + dest += r * 8; + + int n = ((length / 8) + 7) / 8; + switch (r) { + case 0: do { + dest += 64; + FILL_8(dest, -8, c); + case 7: FILL_8(dest, -7, c); + case 6: FILL_8(dest, -6, c); + case 5: FILL_8(dest, -5, c); + case 4: FILL_8(dest, -4, c); + case 3: FILL_8(dest, -3, c); + case 2: FILL_8(dest, -2, c); + case 1: FILL_8(dest, -1, c); + } while (--n > 0); + } + } + + // 32-bit cell to fill? + if (length & 4) { + FILL_4(dest, 0, color); + if (bpp <= 16) + dest += 4; + } + + // 16-bit cell to fill? + if (bpp <= 16 && (length & 2)) { + FILL_2(dest, 0, color); + if (bpp <= 8) + dest += 2; + } + + // 8-bit cell to fill? + if (bpp <= 8 && (length & 1)) + FILL_1(dest, 0, color); + +#undef FILL_1 +#undef FILL_2 +#undef FILL_4 +#undef FILL_8 } -static void accl_invrect(accl_params *p) +void NQD_fillrect(uint32 p) { - D(bug("accl_invrect\n")); + D(bug("accl_fillrect %08x\n", p)); - // 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; + // Get filling parameters + int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); + int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); + int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); + int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); + uint32 color = ReadMacInt32(p + acclPenMode) == 8 ? ReadMacInt32(p + acclForePen) : ReadMacInt32(p + acclBackPen); 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 + D(bug(" width %d, height %d\n", width, height)); + D(bug(" bytes_per_row %d color %08x\n", (int32)ReadMacInt32(p + acclDestRowBytes), color)); - // And perform the inversion - invrect_hook(dest_X, dest_Y, dest_X_max, dest_Y_max); + // And perform the fill + const int bpp = bytes_per_pixel(ReadMacInt32(p + acclDestPixelSize)); + const int dest_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); + uint8 *dest = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dest_row_bytes) + (dest_X * bpp)); + width *= bpp; + switch (bpp) { + case 1: + for (int i = 0; i < height; i++) { + memset(dest, color, width); + dest += dest_row_bytes; + } + break; + case 2: + for (int i = 0; i < height; i++) { + do_fillrect<16>(dest, color, width); + dest += dest_row_bytes; + } + break; + case 4: + for (int i = 0; i < height; i++) { + do_fillrect<32>(dest, color, width); + dest += dest_row_bytes; + } + break; + } } -static bool accl_fillrect_hook(accl_params *p) +bool NQD_fillrect_hook(uint32 p) { - D(bug("accl_fillrect_hook %p\n", p)); + D(bug("accl_fillrect_hook %08x\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) { + if (ReadMacInt32(p + 0x284) != 0 && ReadMacInt32(p + acclDestPixelSize) >= 8) { + const int transfer_mode = ReadMacInt32(p + acclTransferMode); + if (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) { + WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_FILLRECT)); + return true; + } + else if (transfer_mode == 10) { // Invert - p->draw_proc = accl_invrect; + WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_INVRECT)); return true; } } return false; } +// Rectangle blitting +// TODO: optimize for VOSF and target pixmap == screen +void NQD_bitblt(uint32 p) +{ + D(bug("accl_bitblt %08x\n", p)); + + // Get blitting parameters + int16 src_X = (int16)ReadMacInt16(p + acclSrcRect + 2) - (int16)ReadMacInt16(p + acclSrcBoundsRect + 2); + int16 src_Y = (int16)ReadMacInt16(p + acclSrcRect + 0) - (int16)ReadMacInt16(p + acclSrcBoundsRect + 0); + int16 dest_X = (int16)ReadMacInt16(p + acclDestRect + 2) - (int16)ReadMacInt16(p + acclDestBoundsRect + 2); + int16 dest_Y = (int16)ReadMacInt16(p + acclDestRect + 0) - (int16)ReadMacInt16(p + acclDestBoundsRect + 0); + int16 width = (int16)ReadMacInt16(p + acclDestRect + 6) - (int16)ReadMacInt16(p + acclDestRect + 2); + int16 height = (int16)ReadMacInt16(p + acclDestRect + 4) - (int16)ReadMacInt16(p + acclDestRect + 0); + D(bug(" src addr %08x, dest addr %08x\n", ReadMacInt32(p + acclSrcBaseAddr), ReadMacInt32(p + acclDestBaseAddr))); + 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(ReadMacInt32(p + acclSrcPixelSize)); + width *= bpp; + if ((int32)ReadMacInt32(p + acclSrcRowBytes) > 0) { + const int src_row_bytes = (int32)ReadMacInt32(p + acclSrcRowBytes); + const int dst_row_bytes = (int32)ReadMacInt32(p + acclDestRowBytes); + uint8 *src = Mac2HostAddr(ReadMacInt32(p + acclSrcBaseAddr) + (src_Y * src_row_bytes) + (src_X * bpp)); + uint8 *dst = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + (dest_Y * dst_row_bytes) + (dest_X * bpp)); + for (int i = 0; i < height; i++) { + memmove(dst, src, width); + src += src_row_bytes; + dst += dst_row_bytes; + } + } + else { + const int src_row_bytes = -(int32)ReadMacInt32(p + acclSrcRowBytes); + const int dst_row_bytes = -(int32)ReadMacInt32(p + acclDestRowBytes); + uint8 *src = Mac2HostAddr(ReadMacInt32(p + acclSrcBaseAddr) + ((src_Y + height - 1) * src_row_bytes) + (src_X * bpp)); + uint8 *dst = Mac2HostAddr(ReadMacInt32(p + acclDestBaseAddr) + ((dest_Y + height - 1) * dst_row_bytes) + (dest_X * bpp)); + for (int i = height - 1; i >= 0; i--) { + memmove(dst, src, width); + src -= src_row_bytes; + dst -= dst_row_bytes; + } + } +} + +/* + BitBlt transfer modes: + 0 : srcCopy + 1 : srcOr + 2 : srcXor + 3 : srcBic + 4 : notSrcCopy + 5 : notSrcOr + 6 : notSrcXor + 7 : notSrcBic + 32 : blend + 33 : addPin + 34 : addOver + 35 : subPin + 36 : transparent + 37 : adMax + 38 : subOver + 39 : adMin + 50 : hilite +*/ + +bool NQD_bitblt_hook(uint32 p) +{ + D(bug("accl_draw_hook %08x\n", p)); + + // Check if we can accelerate this bitblt + if (ReadMacInt32(p + 0x018) + ReadMacInt32(p + 0x128) == 0 && + ReadMacInt32(p + 0x130) == 0 && + ReadMacInt32(p + acclSrcPixelSize) >= 8 && + ReadMacInt32(p + acclSrcPixelSize) == ReadMacInt32(p + acclDestPixelSize) && + (ReadMacInt32(p + acclSrcRowBytes) ^ ReadMacInt32(p + acclDestRowBytes)) >= 0 && // same sign? + ReadMacInt32(p + acclTransferMode) == 0 && // srcCopy? + ReadMacInt32(p + 0x15c) > 0) { + + // Yes, set function pointer + WriteMacInt32(p + acclDrawProc, NativeTVECT(NATIVE_BITBLT)); + return true; + } + return false; +} + // Wait for graphics operation to finish -static bool accl_sync_hook(void *arg) +bool NQD_sync_hook(uint32 arg) { - D(bug("accl_sync_hook %p\n", arg)); - if (sync_hook != NULL) - sync_hook(); + D(bug("accl_sync_hook %08x\n", arg)); return true; } -static struct accl_hook_info bitblt_hook_info = {accl_bitblt_hook, accl_sync_hook, ACCL_BITBLT}; -static struct accl_hook_info fillrect_hook_info = {accl_fillrect_hook, accl_sync_hook, ACCL_FILLRECT}; -#endif - void VideoInstallAccel(void) { + // Temporary hack until it's fixed for e.g. little-endian & 64-bit platforms +#ifndef __powerpc__ + return; +#endif + // Install acceleration hooks if (PrefsFindBool("gfxaccel")) { D(bug("Video: Installing acceleration hooks\n")); -//!! NQDMisc(6, &bitblt_hook_info); -// NQDMisc(6, &fillrect_hook_info); + 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); + NQDMisc(6, bitblt_hook_info.ptr()); + + SheepVar fillrect_hook_info(sizeof(accl_hook_info)); + base = fillrect_hook_info.addr(); + WriteMacInt32(base + 0, NativeTVECT(NATIVE_FILLRECT_HOOK)); + WriteMacInt32(base + 4, NativeTVECT(NATIVE_SYNC_HOOK)); + WriteMacInt32(base + 8, ACCL_FILLRECT); + NQDMisc(6, fillrect_hook_info.ptr()); } } @@ -1790,6 +2087,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 */ @@ -1999,6 +2306,9 @@ static void *redraw_func(void *arg) XF86DGADirectVideo(x_display, screen, 0); XUngrabPointer(x_display, CurrentTime); XUngrabKeyboard(x_display, CurrentTime); + XUnmapWindow(x_display, the_win); + wait_unmapped(the_win); + XDestroyWindow(x_display, the_win); #endif XSync(x_display, false); XDisplayUnlock(); @@ -2031,7 +2341,7 @@ 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);