ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_x.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/video_x.cpp (file contents):
Revision 1.68 by gbeauche, 2002-09-28T12:42:39Z vs.
Revision 1.84 by gbeauche, 2008-01-01T09:40:33Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  Basilisk II (C) 1997-2002 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 62 | Line 62
62   #include "prefs.h"
63   #include "user_strings.h"
64   #include "video.h"
65 + #include "video_blit.h"
66  
67   #define DEBUG 0
68   #include "debug.h"
# Line 98 | Line 99 | static bool redraw_thread_active = false
99   #ifdef HAVE_PTHREADS
100   static pthread_attr_t redraw_thread_attr;                       // Redraw thread attributes
101   static volatile bool redraw_thread_cancel;                      // Flag: Cancel Redraw thread
102 + static volatile bool redraw_thread_cancel_ack;          // Flag: Acknowledge for redraw thread cancellation
103   static pthread_t redraw_thread;                                         // Redraw thread
104   #endif
105  
# Line 122 | Line 124 | static bool use_keycodes = false;                                      //
124   static int keycode_table[256];                                          // X keycode -> Mac keycode translation table
125  
126   // X11 variables
127 + char *x_display_name = NULL;                                            // X11 display name
128 + Display *x_display = NULL;                                                      // X11 display handle
129   static int screen;                                                                      // Screen number
130   static Window rootwin;                                                          // Root window and our window
131   static int num_depths = 0;                                                      // Number of available X depths
# Line 131 | Line 135 | static unsigned long black_pixel, white_
135   static int eventmask;
136  
137   static int xdepth;                                                                      // Depth of X screen
138 + static VisualFormat visualFormat;
139   static XVisualInfo visualInfo;
140   static Visual *vis;
141   static int color_class;
142  
143 + static bool x_native_byte_order;                                                // XImage has native byte order?
144   static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes
145  
146   static Colormap cmap[2] = {0, 0};                                       // Colormaps for indexed modes (DGA needs two of them)
147  
148 < static XColor x_palette[256];                                                   // Color palette to be used as CLUT and gamma table
148 > static XColor x_palette[256];                                           // Color palette to be used as CLUT and gamma table
149   static bool x_palette_changed = false;                          // Flag: Palette changed, redraw thread must set new colors
150  
151   #ifdef ENABLE_FBDEV_DGA
# Line 192 | Line 198 | extern Display *x_display;
198   // From sys_unix.cpp
199   extern void SysMountFirstFloppy(void);
200  
201 + // From clip_unix.cpp
202 + extern void ClipboardSelectionClear(XSelectionClearEvent *);
203 + extern void ClipboardSelectionRequest(XSelectionRequestEvent *);
204 +
205  
206   /*
207   *  monitor_desc subclass for X11 display
# Line 214 | Line 224 | public:
224   *  Utility functions
225   */
226  
227 + // Map video_mode depth ID to numerical depth value
228 + static inline int depth_of_video_mode(video_mode const & mode)
229 + {
230 +        int depth = -1;
231 +        switch (mode.depth) {
232 +        case VDEPTH_1BIT:
233 +                depth = 1;
234 +                break;
235 +        case VDEPTH_2BIT:
236 +                depth = 2;
237 +                break;
238 +        case VDEPTH_4BIT:
239 +                depth = 4;
240 +                break;
241 +        case VDEPTH_8BIT:
242 +                depth = 8;
243 +                break;
244 +        case VDEPTH_16BIT:
245 +                depth = 16;
246 +                break;
247 +        case VDEPTH_32BIT:
248 +                depth = 32;
249 +                break;
250 +        default:
251 +                abort();
252 +        }
253 +        return depth;
254 + }
255 +
256   // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals)
257 < static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue)
257 > static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue, bool fix_byte_order = false)
258   {
259 <        return ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift);
259 >        uint32 val = ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift);
260 >        if (fix_byte_order && !x_native_byte_order) {
261 >                // We have to fix byte order in the ExpandMap[]
262 >                // NOTE: this is only an optimization since Screen_blitter_init()
263 >                // could be arranged to choose an NBO or OBO (with
264 >                // byteswapping) Blit_Expand_X_To_Y() function
265 >                switch (visualFormat.depth) {
266 >                case 15: case 16:
267 >                        val = do_byteswap_16(val);
268 >                        break;
269 >                case 24: case 32:
270 >                        val = do_byteswap_32(val);
271 >                        break;
272 >                }
273 >        }
274 >        return val;
275   }
276  
277   // Do we have a visual for handling the specified Mac depth? If so, set the
# Line 443 | Line 497 | static int error_handler(Display *d, XEr
497  
498  
499   /*
500 + *  Framebuffer allocation routines
501 + */
502 +
503 + #ifdef ENABLE_VOSF
504 + #include "vm_alloc.h"
505 +
506 + static void *vm_acquire_framebuffer(uint32 size)
507 + {
508 +        // always try to allocate framebuffer at the same address
509 +        static void *fb = VM_MAP_FAILED;
510 +        if (fb != VM_MAP_FAILED) {
511 +                if (vm_acquire_fixed(fb, size) < 0)
512 +                        fb = VM_MAP_FAILED;
513 +        }
514 +        if (fb == VM_MAP_FAILED)
515 +                fb = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT);
516 +        return fb;
517 + }
518 +
519 + static inline void vm_release_framebuffer(void *fb, uint32 size)
520 + {
521 +        vm_release(fb, size);
522 + }
523 + #endif
524 +
525 +
526 + /*
527   *  Display "driver" classes
528   */
529  
# Line 503 | Line 584 | private:
584          int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
585   };
586  
587 + class driver_dga;
588 + static void update_display_dga_vosf(driver_dga *drv);
589 +
590 + class driver_dga : public driver_base {
591 +        friend void update_display_dga_vosf(driver_dga *drv);
592 +
593 + public:
594 +        driver_dga(X11_monitor_desc &monitor);
595 +        ~driver_dga();
596 +
597 +        void suspend(void);
598 +        void resume(void);
599 +
600 + protected:
601 +        struct FakeXImage {
602 +                int width, height;              // size of image
603 +                int depth;                              // depth of image
604 +                int bytes_per_line;             // accelerator to next line
605 +
606 +                FakeXImage(int w, int h, int d)
607 +                        : width(w), height(h), depth(d)
608 +                        { bytes_per_line = TrivialBytesPerRow(width, DepthModeForPixelDepth(depth)); }
609 +        };
610 +        FakeXImage *img;
611 +
612 + private:
613 +        Window suspend_win;             // "Suspend" information window
614 +        void *fb_save;                  // Saved frame buffer for suspend/resume
615 + };
616 +
617   static driver_base *drv = NULL; // Pointer to currently used driver object
618  
619   #ifdef ENABLE_VOSF
# Line 547 | Line 658 | driver_base::~driver_base()
658                  // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
659                  if (the_buffer != VM_MAP_FAILED) {
660                          D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
661 <                        vm_release(the_buffer, the_buffer_size);
661 >                        vm_release_framebuffer(the_buffer, the_buffer_size);
662                          the_buffer = NULL;
663                  }
664                  if (the_host_buffer) {
# Line 697 | Line 808 | driver_window::driver_window(X11_monitor
808          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
809          the_host_buffer = the_buffer_copy;
810          the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
811 <        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
811 >        the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
812          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
813          D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
814   #else
# Line 718 | Line 829 | driver_window::driver_window(X11_monitor
829          XDefineCursor(x_display, w, mac_cursor);
830  
831          // Init blitting routines
721        bool native_byte_order;
722 #ifdef WORDS_BIGENDIAN
723        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
724 #else
725        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
726 #endif
832   #ifdef ENABLE_VOSF
833 <        Screen_blitter_init(&visualInfo, native_byte_order, mode.depth);
833 >        Screen_blitter_init(visualFormat, x_native_byte_order, depth_of_video_mode(mode));
834   #endif
835  
836          // Set frame buffer base
837 <        set_mac_frame_buffer(monitor, mode.depth, native_byte_order);
837 >        set_mac_frame_buffer(monitor, mode.depth, x_native_byte_order);
838  
839          // Everything went well
840          init_ok = true;
# Line 844 | Line 949 | void driver_window::mouse_moved(int x, i
949   *  DGA display driver base class
950   */
951  
847 class driver_dga : public driver_base {
848 public:
849        driver_dga(X11_monitor_desc &monitor);
850        ~driver_dga();
851
852        void suspend(void);
853        void resume(void);
854
855 private:
856        Window suspend_win;             // "Suspend" information window
857        void *fb_save;                  // Saved frame buffer for suspend/resume
858 };
859
952   driver_dga::driver_dga(X11_monitor_desc &m)
953 < : driver_base(m), suspend_win(0), fb_save(NULL)
953 >        : driver_base(m), suspend_win(0), fb_save(NULL), img(NULL)
954   {
955   }
956  
# Line 866 | Line 958 | driver_dga::~driver_dga()
958   {
959          XUngrabPointer(x_display, CurrentTime);
960          XUngrabKeyboard(x_display, CurrentTime);
961 +
962 +        if (img)
963 +                delete img;
964   }
965  
966   // Suspend emulation
# Line 1086 | Line 1181 | driver_fbdev::driver_fbdev(X11_monitor_d
1181   #if REAL_ADDRESSING || DIRECT_ADDRESSING
1182          // Screen_blitter_init() returns TRUE if VOSF is mandatory
1183          // i.e. the framebuffer update function is not Blit_Copy_Raw
1184 <        use_vosf = Screen_blitter_init(&visualInfo, true, mode.depth);
1184 >        use_vosf = Screen_blitter_init(visualFormat, true, mode.depth);
1185          
1186          if (use_vosf) {
1187            // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1188            the_host_buffer = the_buffer;
1189            the_buffer_size = page_extend((height + 2) * bytes_per_row);
1190            the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1191 <          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1191 >          the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
1192 >
1193 >          // Fake image for DGA/VOSF mode to know about display bounds
1194 >          img = new FakeXImage(width, height, depth_of_video_mode(mode));
1195          }
1196   #else
1197          use_vosf = false;
# Line 1217 | Line 1315 | driver_xf86dga::driver_xf86dga(X11_monit
1315          // Init blitting routines
1316          int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth);
1317   #if ENABLE_VOSF
1220        bool native_byte_order;
1221 #ifdef WORDS_BIGENDIAN
1222        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
1223 #else
1224        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
1225 #endif
1318   #if REAL_ADDRESSING || DIRECT_ADDRESSING
1319          // Screen_blitter_init() returns TRUE if VOSF is mandatory
1320          // i.e. the framebuffer update function is not Blit_Copy_Raw
1321 <        use_vosf = Screen_blitter_init(&visualInfo, native_byte_order, mode.depth);
1321 >        use_vosf = Screen_blitter_init(visualFormat, x_native_byte_order, depth_of_video_mode(mode));
1322          
1323          if (use_vosf) {
1324            // Allocate memory for frame buffer (SIZE is extended to page-boundary)
1325            the_host_buffer = the_buffer;
1326            the_buffer_size = page_extend((height + 2) * bytes_per_row);
1327            the_buffer_copy = (uint8 *)malloc(the_buffer_size);
1328 <          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
1328 >          the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
1329 >
1330 >          // Fake image for DGA/VOSF mode to know about display bounds
1331 >          img = new FakeXImage((v_width + 7) & ~7, height, depth_of_video_mode(mode));
1332          }
1333   #else
1334          use_vosf = false;
# Line 1315 | Line 1410 | static void keycode_init(void)
1410  
1411                  // Search for server vendor string, then read keycodes
1412                  const char *vendor = ServerVendor(x_display);
1413 +                // Force use of MacX mappings on MacOS X with Apple's X server
1414 +                int dummy;
1415 +                if (XQueryExtension(x_display, "Apple-DRI", &dummy, &dummy, &dummy))
1416 +                        vendor = "MacX";
1417                  bool vendor_found = false;
1418                  char line[256];
1419                  while (fgets(line, 255, f)) {
# Line 1368 | Line 1467 | bool X11_monitor_desc::video_open(void)
1467                  return false;
1468          }
1469  
1470 +        // Determine the byte order of an XImage content
1471 + #ifdef WORDS_BIGENDIAN
1472 +        x_native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
1473 + #else
1474 +        x_native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
1475 + #endif
1476 +
1477 +        // Build up visualFormat structure
1478 +        visualFormat.fullscreen = (display_type == DISPLAY_DGA);
1479 +        visualFormat.depth = visualInfo.depth;
1480 +        visualFormat.Rmask = visualInfo.red_mask;
1481 +        visualFormat.Gmask = visualInfo.green_mask;
1482 +        visualFormat.Bmask = visualInfo.blue_mask;
1483 +
1484          // Create color maps
1485          if (color_class == PseudoColor || color_class == DirectColor) {
1486                  cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll);
# Line 1428 | Line 1541 | bool X11_monitor_desc::video_open(void)
1541          // Load gray ramp to 8->16/32 expand map
1542          if (!IsDirectMode(mode) && xdepth > 8)
1543                  for (int i=0; i<256; i++)
1544 <                        ExpandMap[i] = map_rgb(i, i, i);
1544 >                        ExpandMap[i] = map_rgb(i, i, i, true);
1545   #endif
1546  
1547          // Create display driver object of requested type
# Line 1473 | Line 1586 | bool X11_monitor_desc::video_open(void)
1586          LOCK_FRAME_BUFFER;
1587  
1588          // Start redraw/input thread
1589 < #ifdef HAVE_PTHREADS
1589 > #ifdef USE_PTHREADS_SERVICES
1590          redraw_thread_cancel = false;
1591          Set_pthread_attr(&redraw_thread_attr, 0);
1592          redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0);
# Line 1669 | Line 1782 | void X11_monitor_desc::video_close(void)
1782          D(bug("video_close()\n"));
1783  
1784          // Stop redraw thread
1785 < #ifdef HAVE_PTHREADS
1785 > #ifdef USE_PTHREADS_SERVICES
1786          if (redraw_thread_active) {
1787                  redraw_thread_cancel = true;
1788 < #ifdef HAVE_PTHREAD_CANCEL
1676 <                pthread_cancel(redraw_thread);
1677 < #endif
1788 >                redraw_thread_cancel_ack = false;
1789                  pthread_join(redraw_thread, NULL);
1790 +                while (!redraw_thread_cancel_ack) ;
1791          }
1792   #endif
1793          redraw_thread_active = false;
# Line 1798 | Line 1910 | void X11_monitor_desc::set_palette(uint8
1910          if (!IsDirectMode(mode) && xdepth > 8) {
1911                  for (int i=0; i<256; i++) {
1912                          int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1913 <                        ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
1913 >                        ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2], true);
1914                  }
1915  
1916                  // We have to redraw everything because the interpretation of pixel values changed
# Line 2003 | Line 2115 | static int event2keycode(XKeyEvent &ev,
2115  
2116   static void handle_events(void)
2117   {
2118 <        while (XPending(x_display)) {
2118 >        for (;;) {
2119                  XEvent event;
2120 <                XNextEvent(x_display, &event);
2120 >                XDisplayLock();
2121 >
2122 >                if (!XCheckMaskEvent(x_display, eventmask, &event)) {
2123 >                        // Handle clipboard events
2124 >                        if (XCheckTypedEvent(x_display, SelectionRequest, &event))
2125 >                                ClipboardSelectionRequest(&event.xselectionrequest);
2126 >                        else if (XCheckTypedEvent(x_display, SelectionClear, &event))
2127 >                                ClipboardSelectionClear(&event.xselectionclear);
2128  
2129 +                        // Window "close" widget clicked
2130 +                        else if (XCheckTypedEvent(x_display, ClientMessage, &event)) {
2131 +                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2132 +                                        ADBKeyDown(0x7f);       // Power key
2133 +                                        ADBKeyUp(0x7f);
2134 +                                }
2135 +                        }
2136 +                        XDisplayUnlock();
2137 +                        break;
2138 +                }
2139 +                
2140                  switch (event.type) {
2141  
2142                          // Mouse button
# Line 2114 | Line 2244 | static void handle_events(void)
2244                                                  memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y);
2245                                  }
2246                                  break;
2117
2118                        // Window "close" widget clicked
2119                        case ClientMessage:
2120                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
2121                                        ADBKeyDown(0x7f);       // Power key
2122                                        ADBKeyUp(0x7f);
2123                                }
2124                                break;
2247                  }
2248 +
2249 +                XDisplayUnlock();
2250          }
2251   }
2252  
# Line 2167 | Line 2291 | static void update_display_dynamic(int t
2291                  }
2292          }
2293  
2294 +        XDisplayLock();
2295          if ((nr_boxes <= max_box) && (nr_boxes)) {
2296                  for (y1=0; y1<16; y1++) {
2297                          for (x1=0; x1<16; x1++) {
# Line 2220 | Line 2345 | static void update_display_dynamic(int t
2345                  }
2346                  nr_boxes = 0;
2347          }
2348 +        XDisplayUnlock();
2349   }
2350  
2351   // Static display update (fixed frame rate, but incremental)
# Line 2329 | Line 2455 | static void update_display_static(driver
2455          }
2456  
2457          // Refresh display
2458 +        XDisplayLock();
2459          if (high && wide) {
2460                  if (drv->have_shm)
2461                          XShmPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high, 0);
2462                  else
2463                          XPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high);
2464          }
2465 +        XDisplayUnlock();
2466   }
2467  
2468  
# Line 2376 | Line 2504 | static inline void handle_palette_change
2504  
2505          if (x_palette_changed) {
2506                  x_palette_changed = false;
2507 +                XDisplayLock();
2508                  drv->update_palette();
2509 +                XDisplayUnlock();
2510          }
2511  
2512          UNLOCK_PALETTE;
# Line 2401 | Line 2531 | static void video_refresh_dga_vosf(void)
2531                  tick_counter = 0;
2532                  if (mainBuffer.dirty) {
2533                          LOCK_VOSF;
2534 <                        update_display_dga_vosf();
2534 >                        update_display_dga_vosf(static_cast<driver_dga *>(drv));
2535                          UNLOCK_VOSF;
2536                  }
2537          }
# Line 2418 | Line 2548 | static void video_refresh_window_vosf(vo
2548          if (++tick_counter >= frame_skip) {
2549                  tick_counter = 0;
2550                  if (mainBuffer.dirty) {
2551 +                        XDisplayLock();
2552                          LOCK_VOSF;
2553                          update_display_window_vosf(static_cast<driver_window *>(drv));
2554                          UNLOCK_VOSF;
2555                          XSync(x_display, false); // Let the server catch up
2556 +                        XDisplayUnlock();
2557                  }
2558          }
2559   }
# Line 2501 | Line 2633 | void VideoRefresh(void)
2633   const int VIDEO_REFRESH_HZ = 60;
2634   const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
2635  
2636 < #ifdef HAVE_PTHREADS
2636 > #ifdef USE_PTHREADS_SERVICES
2637   static void *redraw_func(void *arg)
2638   {
2639          int fd = ConnectionNumber(x_display);
# Line 2542 | Line 2674 | static void *redraw_func(void *arg)
2674          }
2675  
2676          uint64 end = GetTicks_usec();
2677 <        D(bug("%Ld refreshes in %Ld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2677 >        D(bug("%lld refreshes in %lld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2678 >
2679 >        redraw_thread_cancel_ack = true;
2680          return NULL;
2681   }
2682   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines