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.26 by cebix, 2000-10-27T17:01:40Z vs.
Revision 1.39 by gbeauche, 2001-06-26T22:35:41Z

# Line 1 | Line 1
1   /*
2   *  video_x.cpp - Video/graphics emulation, X11 specific stuff
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
4 > *  Basilisk II (C) 1997-2001 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 53 | Line 53
53   #endif
54  
55   #ifdef ENABLE_VOSF
56 # include <unistd.h>
57 # include <signal.h>
56   # include <fcntl.h>
57   # include <sys/mman.h>
58 + # include "sigsegv.h"
59 + # include "vm_alloc.h"
60   #endif
61  
62   #include "cpu_emulation.h"
# Line 122 | Line 122 | static Colormap cmap[2];                                                       // Two co
122   static XColor black, white;
123   static unsigned long black_pixel, white_pixel;
124   static int eventmask;
125 < static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | FocusChangeMask | ExposureMask;
126 < static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
125 > static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask;
126 > static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask;
127 > static Atom WM_DELETE_WINDOW = (Atom)0;
128  
129   static XColor palette[256];                                                     // Color palette for 8-bit mode
130   static bool palette_changed = false;                            // Flag: Palette changed, redraw thread must set new colors
131   #ifdef HAVE_PTHREADS
132   static pthread_mutex_t palette_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect palette
133 + #define LOCK_PALETTE pthread_mutex_lock(&palette_lock)
134 + #define UNLOCK_PALETTE pthread_mutex_unlock(&palette_lock)
135 + #else
136 + #define LOCK_PALETTE
137 + #define UNLOCK_PALETTE
138   #endif
139  
140   // Variables for window mode
# Line 149 | Line 155 | static Window suspend_win;                                                     // "Sus
155   static void *fb_save = NULL;                                            // Saved frame buffer for suspend
156   #ifdef HAVE_PTHREADS
157   static pthread_mutex_t frame_buffer_lock = PTHREAD_MUTEX_INITIALIZER;   // Mutex to protect frame buffer
158 + #define LOCK_FRAME_BUFFER pthread_mutex_lock(&frame_buffer_lock);
159 + #define UNLOCK_FRAME_BUFFER pthread_mutex_unlock(&frame_buffer_lock);
160 + #else
161 + #define LOCK_FRAME_BUFFER
162 + #define UNLOCK_FRAME_BUFFER
163   #endif
164  
165   // Variables for fbdev DGA mode
# Line 168 | Line 179 | static const bool use_vosf = false;
179   #endif
180  
181   #ifdef ENABLE_VOSF
182 < static uint8 * the_host_buffer;                                         // Host frame buffer in VOSF mode
182 > // Variables for Video on SEGV support (taken from the Win32 port)
183 > static uint8 *the_host_buffer;                                          // Host frame buffer in VOSF mode
184   static uint32 the_buffer_size;                                          // Size of allocated the_buffer
173 #endif
185  
175 #ifdef ENABLE_VOSF
176 // Variables for Video on SEGV support (taken from the Win32 port)
186   struct ScreenPageInfo {
187      int top, bottom;                    // Mapping between this virtual page and Mac scanlines
188   };
189  
190   struct ScreenInfo {
191 <    uint32 memBase;                             // Real start address
192 <    uint32 memStart;                    // Start address aligned to page boundary
193 <    uint32 memEnd;                              // Address of one-past-the-end of the screen
191 >    uintptr memBase;                    // Real start address
192 >    uintptr memStart;                   // Start address aligned to page boundary
193 >    uintptr memEnd;                             // Address of one-past-the-end of the screen
194      uint32 memLength;                   // Length of the memory addressed by the screen pages
195      
196      uint32 pageSize;                    // Size of a page
197      int pageBits;                               // Shift count to get the page number
198      uint32 pageCount;                   // Number of pages allocated to the screen
199      
200 <    uint8 * dirtyPages;                 // Table of flags set if page was altered
200 >        bool dirty;                                     // Flag: set if the frame buffer was touched
201 >    char * dirtyPages;                  // Table of flags set if page was altered
202      ScreenPageInfo * pageInfo;  // Table of mappings page -> Mac scanlines
203   };
204  
205   static ScreenInfo mainBuffer;
206  
207 < #define PFLAG_SET(page)                 mainBuffer.dirtyPages[page] = 1
208 < #define PFLAG_CLEAR(page)               mainBuffer.dirtyPages[page] = 0
209 < #define PFLAG_ISSET(page)               mainBuffer.dirtyPages[page]
210 < #define PFLAG_ISCLEAR(page)             (mainBuffer.dirtyPages[page] == 0)
207 > #define PFLAG_SET_VALUE                 0x00
208 > #define PFLAG_CLEAR_VALUE               0x01
209 > #define PFLAG_SET_VALUE_4               0x00000000
210 > #define PFLAG_CLEAR_VALUE_4             0x01010101
211 > #define PFLAG_SET(page)                 mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE
212 > #define PFLAG_CLEAR(page)               mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE
213 > #define PFLAG_ISSET(page)               (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE)
214 > #define PFLAG_ISCLEAR(page)             (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE)
215 >
216   #ifdef UNALIGNED_PROFITABLE
217 < # define PFLAG_ISCLEAR_4(page)  (*((uint32 *)(mainBuffer.dirtyPages + page)) == 0)
217 > # define PFLAG_ISSET_4(page)    (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4)
218 > # define PFLAG_ISCLEAR_4(page)  (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4)
219 > #else
220 > # define PFLAG_ISSET_4(page) \
221 >                PFLAG_ISSET(page  ) && PFLAG_ISSET(page+1) \
222 >        &&      PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3)
223 > # define PFLAG_ISCLEAR_4(page) \
224 >                PFLAG_ISCLEAR(page  ) && PFLAG_ISCLEAR(page+1) \
225 >        &&      PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3)
226 > #endif
227 >
228 > // Set the selected page range [ first_page, last_page [ into the SET state
229 > #define PFLAG_SET_RANGE(first_page, last_page) \
230 >        memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \
231 >                (last_page) - (first_page))
232 >
233 > // Set the selected page range [ first_page, last_page [ into the CLEAR state
234 > #define PFLAG_CLEAR_RANGE(first_page, last_page) \
235 >        memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \
236 >                (last_page) - (first_page))
237 >
238 > #define PFLAG_SET_ALL do { \
239 >        PFLAG_SET_RANGE(0, mainBuffer.pageCount); \
240 >        mainBuffer.dirty = true; \
241 > } while (0)
242 >
243 > #define PFLAG_CLEAR_ALL do { \
244 >        PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \
245 >        mainBuffer.dirty = false; \
246 > } while (0)
247 >
248 > // Set the following macro definition to 1 if your system
249 > // provides a really fast strchr() implementation
250 > //#define HAVE_FAST_STRCHR 0
251 >
252 > static inline int find_next_page_set(int page)
253 > {
254 > #if HAVE_FAST_STRCHR
255 >        char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE);
256 >        return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
257   #else
258 < # define PFLAG_ISCLEAR_4(page)  \
259 <                (mainBuffer.dirtyPages[page  ] == 0) \
260 <        &&      (mainBuffer.dirtyPages[page+1] == 0) \
261 <        &&      (mainBuffer.dirtyPages[page+2] == 0) \
262 <        &&      (mainBuffer.dirtyPages[page+3] == 0)
258 >        while (PFLAG_ISCLEAR_4(page))
259 >                page += 4;
260 >        while (PFLAG_ISCLEAR(page))
261 >                page++;
262 >        return page;
263   #endif
264 < #define PFLAG_CLEAR_ALL                 memset(mainBuffer.dirtyPages, 0, mainBuffer.pageCount)
265 < #define PFLAG_SET_ALL                   memset(mainBuffer.dirtyPages, 1, mainBuffer.pageCount)
264 > }
265 >
266 > static inline int find_next_page_clear(int page)
267 > {
268 > #if HAVE_FAST_STRCHR
269 >        char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE);
270 >        return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
271 > #else
272 >        while (PFLAG_ISSET_4(page))
273 >                page += 4;
274 >        while (PFLAG_ISSET(page))
275 >                page++;
276 >        return page;
277 > #endif
278 > }
279  
280   static int zero_fd = -1;
214 static bool Screen_fault_handler_init();
215 static struct sigaction vosf_sa;
281  
282   #ifdef HAVE_PTHREADS
283 < static pthread_mutex_t Screen_draw_lock = PTHREAD_MUTEX_INITIALIZER;    // Mutex to protect frame buffer (dirtyPages in fact)
283 > static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER;   // Mutex to protect frame buffer (dirtyPages in fact)
284 > #define LOCK_VOSF pthread_mutex_lock(&vosf_lock);
285 > #define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock);
286 > #else
287 > #define LOCK_VOSF
288 > #define UNLOCK_VOSF
289   #endif
290  
291   static int log_base_2(uint32 x)
# Line 228 | Line 298 | static int log_base_2(uint32 x)
298          }
299          return l;
300   }
301 <
232 < #endif
301 > #endif /* ENABLE_VOSF */
302  
303   // VideoRefresh function
304   void VideoRefreshInit(void);
# Line 237 | Line 306 | static void (*video_refresh)(void);
306  
307   // Prototypes
308   static void *redraw_func(void *arg);
309 < static int event2keycode(XKeyEvent *ev);
309 > static int event2keycode(XKeyEvent &ev);
310  
311  
312   // From main_unix.cpp
# Line 307 | Line 376 | void set_video_monitor(int width, int he
376          VideoMonitor.bytes_per_row = bytes_per_row;
377   }
378  
379 + // Set window name and class
380 + static void set_window_name(Window w, int name)
381 + {
382 +        const char *str = GetString(name);
383 +        XStoreName(x_display, w, str);
384 +        XSetIconName(x_display, w, str);
385 +
386 +        XClassHint *hints;
387 +        hints = XAllocClassHint();
388 +        if (hints) {
389 +                hints->res_name = "BasiliskII";
390 +                hints->res_class = "BasiliskII";
391 +                XSetClassHint(x_display, w, hints);
392 +                XFree(hints);
393 +        }
394 + }
395 +
396 + // Set window input focus flag
397 + static void set_window_focus(Window w)
398 + {
399 +        XWMHints *hints = XAllocWMHints();
400 +        if (hints) {
401 +                hints->input = True;
402 +                hints->initial_state = NormalState;
403 +                hints->flags = InputHint | StateHint;
404 +                XSetWMHints(x_display, w, hints);
405 +                XFree(hints);
406 +        }
407 + }
408 +
409 + // Set WM_DELETE_WINDOW protocol on window (preventing it from being destroyed by the WM when clicking on the "close" widget)
410 + static void set_window_delete_protocol(Window w)
411 + {
412 +        WM_DELETE_WINDOW = XInternAtom(x_display, "WM_DELETE_WINDOW", false);
413 +        XSetWMProtocols(x_display, w, &WM_DELETE_WINDOW, 1);
414 + }
415 +
416 + // Wait until window is mapped/unmapped
417 + void wait_mapped(Window w)
418 + {
419 +        XEvent e;
420 +        do {
421 +                XMaskEvent(x_display, StructureNotifyMask, &e);
422 +        } while ((e.type != MapNotify) || (e.xmap.event != w));
423 + }
424 +
425 + void wait_unmapped(Window w)
426 + {
427 +        XEvent e;
428 +        do {
429 +                XMaskEvent(x_display, StructureNotifyMask, &e);
430 +        } while ((e.type != UnmapNotify) || (e.xmap.event != w));
431 + }
432 +
433   // Trap SHM errors
434   static bool shm_error = false;
435   static int (*old_error_handler)(Display *, XErrorEvent *);
# Line 336 | Line 459 | static bool init_window(int width, int h
459          XSetWindowAttributes wattr;
460          wattr.event_mask = eventmask = win_eventmask;
461          wattr.background_pixel = black_pixel;
462 <        wattr.border_pixel = black_pixel;
340 <        wattr.backing_store = NotUseful;
341 <        wattr.save_under = false;
342 <        wattr.backing_planes = xdepth;
462 >        wattr.colormap = cmap[0];
463  
344        XSync(x_display, false);
464          the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
465 <                InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel |
466 <                CWBackingStore | CWBackingPlanes, &wattr);
465 >                InputOutput, vis, CWEventMask | CWBackPixel | (depth == 8 ? CWColormap : 0), &wattr);
466 >
467 >        // Set window name/class
468 >        set_window_name(the_win, STR_WINDOW_TITLE);
469  
470          // Indicate that we want keyboard input
471 <        {
472 <                XWMHints *hints = XAllocWMHints();
473 <                if (hints) {
474 <                        hints->input = True;
354 <                        hints->flags = InputHint;
355 <                        XSetWMHints(x_display, the_win, hints);
356 <                        XFree((char *)hints);
357 <                }
358 <        }
471 >        set_window_focus(the_win);
472 >
473 >        // Set delete protocol property
474 >        set_window_delete_protocol(the_win);
475  
476          // Make window unresizable
477          {
# Line 367 | Line 483 | static bool init_window(int width, int h
483                          hints->max_height = height;
484                          hints->flags = PMinSize | PMaxSize;
485                          XSetWMNormalHints(x_display, the_win, hints);
486 <                        XFree((char *)hints);
486 >                        XFree(hints);
487                  }
488          }
489          
374        // Set window title
375        {
376                XTextProperty title_prop;
377                const char *title = GetString(STR_WINDOW_TITLE);
378                XStringListToTextProperty((char **)&title, 1, &title_prop);
379                XSetWMName(x_display, the_win, &title_prop);
380                XFree(title_prop.value);
381        }
382
383        // Set window class
384        {
385                XClassHint *hints;
386                hints = XAllocClassHint();
387                if (hints) {
388                        hints->res_name = "BasiliskII";
389                        hints->res_class = "BasiliskII";
390                        XSetClassHint(x_display, the_win, hints);
391                        XFree((char *)hints);
392                }
393        }
394
490          // Show window
491 <        XSync(x_display, false);
492 <        XMapRaised(x_display, the_win);
398 <        XFlush(x_display);
399 <
400 <        // Set colormap
401 <        if (depth == 8)
402 <                XSetWindowColormap(x_display, the_win, cmap[0]);
491 >        XMapWindow(x_display, the_win);
492 >        wait_mapped(the_win);
493  
494          // Try to create and attach SHM image
495          have_shm = false;
# Line 455 | Line 545 | static bool init_window(int width, int h
545          }
546  
547   #ifdef ENABLE_VOSF
548 <        // Allocate a page-aligned chunk of memory for frame buffer
459 <        the_buffer_size = align_on_page_boundary((aligned_height + 2) * img->bytes_per_line);
548 >        // Allocate memory for frame buffer (SIZE is extended to page-boundary)
549          the_host_buffer = the_buffer_copy;
550 <        
551 <        the_buffer_copy = (uint8 *)allocate_framebuffer(the_buffer_size);
552 <        memset(the_buffer_copy, 0, the_buffer_size);
464 <        
465 <        the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size);
466 <        memset(the_buffer, 0, the_buffer_size);
550 >        the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
551 >        the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
552 >        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
553   #else
554          // Allocate memory for frame buffer
555          the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
# Line 483 | Line 569 | static bool init_window(int width, int h
569          // Set VideoMonitor
570          bool native_byte_order;
571   #ifdef WORDS_BIGENDIAN
572 <        native_byte_order = (img->bitmap_bit_order == MSBFirst);
572 >        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
573   #else
574 <        native_byte_order = (img->bitmap_bit_order == LSBFirst);
574 >        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
575   #endif
576   #ifdef ENABLE_VOSF
577 <        do_update_framebuffer = GET_FBCOPY_FUNC(depth, native_byte_order, DISPLAY_WINDOW);
577 >        Screen_blitter_init(&visualInfo, native_byte_order);
578   #endif
579          set_video_monitor(width, height, img->bytes_per_line, native_byte_order);
580          
# Line 572 | Line 658 | static bool init_fbdev_dga(char *in_fb_n
658          
659          // Create window
660          XSetWindowAttributes wattr;
661 <        wattr.override_redirect = True;
662 <        wattr.backing_store             = NotUseful;
663 <        wattr.background_pixel  = white_pixel;
664 <        wattr.border_pixel              = black_pixel;
579 <        wattr.event_mask                = eventmask = dga_eventmask;
661 >        wattr.event_mask = eventmask = dga_eventmask;
662 >        wattr.background_pixel = white_pixel;
663 >        wattr.override_redirect = True;
664 >        wattr.colormap = cmap[0];
665          
581        XSync(x_display, false);
666          the_win = XCreateWindow(x_display, rootwin,
667                  0, 0, width, height,
668                  0, xdepth, InputOutput, vis,
669 <                CWEventMask|CWBackPixel|CWBorderPixel|CWOverrideRedirect|CWBackingStore,
669 >                CWEventMask | CWBackPixel | CWOverrideRedirect | (depth == 8 ? CWColormap : 0),
670                  &wattr);
671 <        XSync(x_display, false);
671 >
672 >        // Set window name/class
673 >        set_window_name(the_win, STR_WINDOW_TITLE);
674 >
675 >        // Indicate that we want keyboard input
676 >        set_window_focus(the_win);
677 >
678 >        // Show window
679          XMapRaised(x_display, the_win);
680 <        XSync(x_display, false);
680 >        wait_mapped(the_win);
681          
682          // Grab mouse and keyboard
683          XGrabKeyboard(x_display, the_win, True,
# Line 595 | Line 686 | static bool init_fbdev_dga(char *in_fb_n
686                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
687                  GrabModeAsync, GrabModeAsync, the_win, None, CurrentTime);
688          
598        // Set colormap
599        if (depth == 8)
600                XSetWindowColormap(x_display, the_win, cmap[0]);
601        
689          // Set VideoMonitor
690          int bytes_per_row = width;
691          switch (depth) {
# Line 626 | Line 713 | static bool init_fbdev_dga(char *in_fb_n
713          
714   #if ENABLE_VOSF
715   #if REAL_ADDRESSING || DIRECT_ADDRESSING
716 <        // If the blit function is null, i.e. just a copy of the buffer,
717 <        // we first try to avoid the allocation of a temporary frame buffer
718 <        use_vosf = true;
632 <        do_update_framebuffer = GET_FBCOPY_FUNC(depth, true, DISPLAY_DGA);
633 <        if (do_update_framebuffer == FBCOPY_FUNC(fbcopy_raw))
634 <                use_vosf = false;
716 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
717 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
718 >        use_vosf = Screen_blitter_init(&visualInfo, true);
719          
720          if (use_vosf) {
721 <                the_host_buffer = the_buffer;
722 <                the_buffer_size = align_on_page_boundary((height + 2) * bytes_per_row);
723 <                the_buffer_copy = (uint8 *)malloc(the_buffer_size);
724 <                memset(the_buffer_copy, 0, the_buffer_size);
725 <                the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size);
642 <                memset(the_buffer, 0, the_buffer_size);
721 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
722 >          the_host_buffer = the_buffer;
723 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
724 >          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
725 >          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
726          }
727   #else
728          use_vosf = false;
# Line 678 | Line 761 | static bool init_xf86_dga(int width, int
761                  }
762                  XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]);
763                  XF86VidModeSetViewPort(x_display, screen, 0, 0);
764 +                XSync(x_display, false);
765          }
766   #endif
767  
768          // Create window
769          XSetWindowAttributes wattr;
770          wattr.event_mask = eventmask = dga_eventmask;
687        wattr.border_pixel = black_pixel;
771          wattr.override_redirect = True;
772  
690        XSync(x_display, false);
773          the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth,
774 <                InputOutput, vis, CWEventMask | CWBorderPixel | CWOverrideRedirect, &wattr);
775 <        XSync(x_display, false);
776 <        XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE));
774 >                InputOutput, vis, CWEventMask | CWOverrideRedirect, &wattr);
775 >
776 >        // Set window name/class
777 >        set_window_name(the_win, STR_WINDOW_TITLE);
778 >
779 >        // Indicate that we want keyboard input
780 >        set_window_focus(the_win);
781 >
782 >        // Show window
783          XMapRaised(x_display, the_win);
784 <        XSync(x_display, false);
784 >        wait_mapped(the_win);
785  
786          // Establish direct screen connection
787          XMoveResizeWindow(x_display, the_win, 0, 0, width, height);
# Line 712 | Line 800 | static bool init_xf86_dga(int width, int
800                  XSetWindowColormap(x_display, the_win, cmap[current_dga_cmap = 0]);
801                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
802          }
803 +        XSync(x_display, false);
804  
805          // Set VideoMonitor
806          int bytes_per_row = (v_width + 7) & ~7;
# Line 728 | Line 817 | static bool init_xf86_dga(int width, int
817                          bytes_per_row *= 4;
818                          break;
819          }
820 <        
820 >
821 > #ifdef VIDEO_VOSF
822   #if REAL_ADDRESSING || DIRECT_ADDRESSING
823 <        // If the blit function is null, i.e. just a copy of the buffer,
824 <        // we first try to avoid the allocation of a temporary frame buffer
825 <        use_vosf = true;
736 <        do_update_framebuffer = GET_FBCOPY_FUNC(depth, true, DISPLAY_DGA);
737 <        if (do_update_framebuffer == FBCOPY_FUNC(fbcopy_raw))
738 <                use_vosf = false;
823 >        // Screen_blitter_init() returns TRUE if VOSF is mandatory
824 >        // i.e. the framebuffer update function is not Blit_Copy_Raw
825 >        use_vosf = Screen_blitter_init(&visualInfo, true);
826          
827          if (use_vosf) {
828 <                the_host_buffer = the_buffer;
829 <                the_buffer_size = align_on_page_boundary((height + 2) * bytes_per_row);
830 <                the_buffer_copy = (uint8 *)malloc(the_buffer_size);
831 <                memset(the_buffer_copy, 0, the_buffer_size);
832 <                the_buffer = (uint8 *)allocate_framebuffer(the_buffer_size);
746 <                memset(the_buffer, 0, the_buffer_size);
828 >          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
829 >          the_host_buffer = the_buffer;
830 >          the_buffer_size = page_extend((height + 2) * bytes_per_row);
831 >          the_buffer_copy = (uint8 *)vm_acquire(the_buffer_size);
832 >          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
833          }
834 < #elif defined(ENABLE_VOSF)
749 <        // The UAE memory handlers will already handle color conversion, if needed.
834 > #else
835          use_vosf = false;
836   #endif
837 + #endif
838          
839          set_video_monitor(width, height, bytes_per_row, true);
840   #if REAL_ADDRESSING || DIRECT_ADDRESSING
# Line 836 | Line 922 | bool VideoInitBuffer()
922                  const uint32 page_size  = getpagesize();
923                  const uint32 page_mask  = page_size - 1;
924                  
925 <                mainBuffer.memBase      = (uint32) the_buffer;
925 >                mainBuffer.memBase      = (uintptr) the_buffer;
926                  // Align the frame buffer on page boundary
927 <                mainBuffer.memStart             = (uint32)((((unsigned long) the_buffer) + page_mask) & ~page_mask);
927 >                mainBuffer.memStart             = (uintptr)((((unsigned long) the_buffer) + page_mask) & ~page_mask);
928                  mainBuffer.memLength    = the_buffer_size;
929                  mainBuffer.memEnd       = mainBuffer.memStart + mainBuffer.memLength;
930  
# Line 849 | Line 935 | bool VideoInitBuffer()
935                  if (mainBuffer.dirtyPages != 0)
936                          free(mainBuffer.dirtyPages);
937  
938 <                mainBuffer.dirtyPages = (uint8 *) malloc(mainBuffer.pageCount);
938 >                mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2);
939  
940                  if (mainBuffer.pageInfo != 0)
941                          free(mainBuffer.pageInfo);
# Line 858 | Line 944 | bool VideoInitBuffer()
944  
945                  if ((mainBuffer.dirtyPages == 0) || (mainBuffer.pageInfo == 0))
946                          return false;
947 +                
948 +                mainBuffer.dirty = false;
949  
950                  PFLAG_CLEAR_ALL;
951 +                // Safety net to insure the loops in the update routines will terminate
952 +                // See a discussion in <video_vosf.h> for further details
953 +                PFLAG_CLEAR(mainBuffer.pageCount);
954 +                PFLAG_SET(mainBuffer.pageCount+1);
955  
956                  uint32 a = 0;
957                  for (int i = 0; i < mainBuffer.pageCount; i++) {
# Line 880 | Line 972 | bool VideoInitBuffer()
972                  }
973                  
974                  // We can now write-protect the frame buffer
975 <                if (mprotect((caddr_t)mainBuffer.memStart, mainBuffer.memLength, PROT_READ) != 0)
975 >                if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
976                          return false;
977          }
978   #endif
# Line 912 | Line 1004 | bool VideoInit(bool classic)
1004          keycode_init();
1005  
1006          // Read prefs
1007 <        mouse_wheel_mode = PrefsFindInt16("mousewheelmode");
1008 <        mouse_wheel_lines = PrefsFindInt16("mousewheellines");
1007 >        mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
1008 >        mouse_wheel_lines = PrefsFindInt32("mousewheellines");
1009  
1010          // Find screen and root window
1011          screen = XDefaultScreen(x_display);
# Line 1050 | Line 1142 | bool VideoInit(bool classic)
1142                          break;
1143          }
1144  
1053 #ifdef HAVE_PTHREADS
1145          // Lock down frame buffer
1146 <        pthread_mutex_lock(&frame_buffer_lock);
1056 < #endif
1146 >        LOCK_FRAME_BUFFER;
1147  
1148   #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
1149          // Set variables for UAE memory mapping
# Line 1075 | Line 1165 | bool VideoInit(bool classic)
1165                  }
1166  
1167                  // Initialize the handler for SIGSEGV
1168 <                if (!Screen_fault_handler_init()) {
1168 >                if (!sigsegv_install_handler(screen_fault_handler)) {
1169                          // TODO: STR_VOSF_INIT_ERR ?
1170                          ErrorAlert("Could not initialize Video on SEGV signals");
1171                          return false;
# Line 1118 | Line 1208 | void VideoExit(void)
1208          }
1209   #endif
1210  
1121 #ifdef HAVE_PTHREADS
1211          // Unlock frame buffer
1212 <        pthread_mutex_unlock(&frame_buffer_lock);
1124 < #endif
1212 >        UNLOCK_FRAME_BUFFER;
1213  
1214          // Close window and server connection
1215          if (x_display != NULL) {
# Line 1168 | Line 1256 | void VideoExit(void)
1256                  }
1257   #ifdef ENABLE_VOSF
1258                  else {
1259 <                        if (the_buffer != (uint8 *)MAP_FAILED) {
1260 <                                munmap((caddr_t)the_buffer, the_buffer_size);
1259 >                        if (the_buffer != (uint8 *)VM_MAP_FAILED) {
1260 >                                vm_release(the_buffer, the_buffer_size);
1261                                  the_buffer = 0;
1262                          }
1263                          
1264 <                        if (the_buffer_copy != (uint8 *)MAP_FAILED) {
1265 <                                munmap((caddr_t)the_buffer_copy, the_buffer_size);
1264 >                        if (the_buffer_copy != (uint8 *)VM_MAP_FAILED) {
1265 >                                vm_release(the_buffer_copy, the_buffer_size);
1266                                  the_buffer_copy = 0;
1267                          }
1268                  }
# Line 1224 | Line 1312 | void VideoInterrupt(void)
1312          if (emerg_quit)
1313                  QuitEmulator();
1314  
1227 #ifdef HAVE_PTHREADS
1315          // Temporarily give up frame buffer lock (this is the point where
1316          // we are suspended when the user presses Ctrl-Tab)
1317 <        pthread_mutex_unlock(&frame_buffer_lock);
1318 <        pthread_mutex_lock(&frame_buffer_lock);
1232 < #endif
1317 >        UNLOCK_FRAME_BUFFER;
1318 >        LOCK_FRAME_BUFFER;
1319   }
1320  
1321  
# Line 1239 | Line 1325 | void VideoInterrupt(void)
1325  
1326   void video_set_palette(uint8 *pal)
1327   {
1328 < #ifdef HAVE_PTHREDS
1243 <        pthread_mutex_lock(&palette_lock);
1244 < #endif
1328 >        LOCK_PALETTE;
1329  
1330          // Convert colors to XColor array
1331          for (int i=0; i<256; i++) {
# Line 1255 | Line 1339 | void video_set_palette(uint8 *pal)
1339          // Tell redraw thread to change palette
1340          palette_changed = true;
1341  
1342 < #ifdef HAVE_PTHREADS
1259 <        pthread_mutex_unlock(&palette_lock);
1260 < #endif
1342 >        UNLOCK_PALETTE;
1343   }
1344  
1345  
# Line 1273 | Line 1355 | static void suspend_emul(void)
1355                  ADBKeyUp(0x36);
1356                  ctrl_down = false;
1357  
1276 #ifdef HAVE_PTHREADS
1358                  // Lock frame buffer (this will stop the MacOS thread)
1359 <                pthread_mutex_lock(&frame_buffer_lock);
1279 < #endif
1359 >                LOCK_FRAME_BUFFER;
1360  
1361                  // Save frame buffer
1362                  fb_save = malloc(VideoMonitor.y * VideoMonitor.bytes_per_row);
# Line 1290 | Line 1370 | static void suspend_emul(void)
1370                  XUngrabPointer(x_display, CurrentTime);
1371                  XUngrabKeyboard(x_display, CurrentTime);
1372                  XUnmapWindow(x_display, the_win);
1373 <                XSync(x_display, false);
1373 >                wait_unmapped(the_win);
1374  
1375                  // Open "suspend" window
1376                  XSetWindowAttributes wattr;
1377                  wattr.event_mask = KeyPressMask;
1378                  wattr.background_pixel = black_pixel;
1299                wattr.border_pixel = black_pixel;
1300                wattr.backing_store = Always;
1301                wattr.backing_planes = xdepth;
1302                wattr.colormap = DefaultColormap(x_display, screen);
1379                  
1304                XSync(x_display, false);
1380                  suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth,
1381 <                        InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel |
1382 <                        CWBackingStore | CWBackingPlanes | (xdepth == 8 ? CWColormap : 0), &wattr);
1383 <                XSync(x_display, false);
1384 <                XStoreName(x_display, suspend_win, GetString(STR_SUSPEND_WINDOW_TITLE));
1310 <                XMapRaised(x_display, suspend_win);
1311 <                XSync(x_display, false);
1381 >                        InputOutput, vis, CWEventMask | CWBackPixel, &wattr);
1382 >                set_window_name(suspend_win, STR_SUSPEND_WINDOW_TITLE);
1383 >                set_window_focus(suspend_win);
1384 >                XMapWindow(x_display, suspend_win);
1385                  emul_suspended = true;
1386          }
1387   }
# Line 1321 | Line 1394 | static void resume_emul(void)
1394  
1395          // Reopen full screen display
1396          XMapRaised(x_display, the_win);
1397 +        wait_mapped(the_win);
1398          XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
1325        XSync(x_display, false);
1399          XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime);
1400          XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
1401   #ifdef ENABLE_XF86_DGA
# Line 1336 | Line 1409 | static void resume_emul(void)
1409          // not necessary.
1410   #ifdef ENABLE_VOSF
1411          if (use_vosf) {
1412 < #ifdef HAVE_PTHREADS
1340 <                pthread_mutex_lock(&Screen_draw_lock);
1341 < #endif
1412 >                LOCK_VOSF;
1413                  PFLAG_SET_ALL;
1414 < #ifdef HAVE_PTHREADS
1344 <                pthread_mutex_unlock(&Screen_draw_lock);
1345 < #endif
1414 >                UNLOCK_VOSF;
1415                  memset(the_buffer_copy, 0, VideoMonitor.bytes_per_row * VideoMonitor.y);
1416          }
1417   #endif
# Line 1363 | Line 1432 | static void resume_emul(void)
1432                  XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
1433   #endif
1434  
1366 #ifdef HAVE_PTHREADS
1435          // Unlock frame buffer (and continue MacOS thread)
1436 <        pthread_mutex_unlock(&frame_buffer_lock);
1436 >        UNLOCK_FRAME_BUFFER;
1437          emul_suspended = false;
1370 #endif
1438   }
1439   #endif
1440  
# Line 1521 | Line 1588 | static int kc_decode(KeySym ks)
1588          return -1;
1589   }
1590  
1591 < static int event2keycode(XKeyEvent *ev)
1591 > static int event2keycode(XKeyEvent &ev)
1592   {
1593          KeySym ks;
1594          int as;
1595          int i = 0;
1596  
1597          do {
1598 <                ks = XLookupKeysym(ev, i++);
1598 >                ks = XLookupKeysym(&ev, i++);
1599                  as = kc_decode(ks);
1600                  if (as != -1)
1601                          return as;
# Line 1544 | Line 1611 | static int event2keycode(XKeyEvent *ev)
1611  
1612   static void handle_events(void)
1613   {
1614 <        XEvent event;
1615 <        for (;;) {
1616 <                if (!XCheckMaskEvent(x_display, eventmask, &event))
1550 <                        break;
1614 >        while (XPending(x_display)) {
1615 >                XEvent event;
1616 >                XNextEvent(x_display, &event);
1617  
1618                  switch (event.type) {
1619                          // Mouse button
1620                          case ButtonPress: {
1621 <                                unsigned int button = ((XButtonEvent *)&event)->button;
1621 >                                unsigned int button = event.xbutton.button;
1622                                  if (button < 4)
1623                                          ADBMouseDown(button - 1);
1624                                  else if (button < 6) {  // Wheel mouse
# Line 1571 | Line 1637 | static void handle_events(void)
1637                                  break;
1638                          }
1639                          case ButtonRelease: {
1640 <                                unsigned int button = ((XButtonEvent *)&event)->button;
1640 >                                unsigned int button = event.xbutton.button;
1641                                  if (button < 4)
1642                                          ADBMouseUp(button - 1);
1643                                  break;
# Line 1579 | Line 1645 | static void handle_events(void)
1645  
1646                          // Mouse moved
1647                          case EnterNotify:
1582                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1583                                break;
1648                          case MotionNotify:
1649 <                                ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y);
1649 >                                ADBMouseMoved(event.xmotion.x, event.xmotion.y);
1650                                  break;
1651  
1652                          // Keyboard
1653                          case KeyPress: {
1654                                  int code;
1655                                  if (use_keycodes) {
1656 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
1657 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
1656 >                                        event2keycode(event.xkey);      // This is called to process the hotkeys
1657 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1658                                  } else
1659 <                                        code = event2keycode((XKeyEvent *)&event);
1659 >                                        code = event2keycode(event.xkey);
1660                                  if (code != -1) {
1661                                          if (!emul_suspended) {
1662                                                  if (code == 0x39) {     // Caps Lock pressed
# Line 1619 | Line 1683 | static void handle_events(void)
1683                          case KeyRelease: {
1684                                  int code;
1685                                  if (use_keycodes) {
1686 <                                        event2keycode((XKeyEvent *)&event);     // This is called to process the hotkeys
1687 <                                        code = keycode_table[((XKeyEvent *)&event)->keycode & 0xff];
1686 >                                        event2keycode(event.xkey);      // This is called to process the hotkeys
1687 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1688                                  } else
1689 <                                        code = event2keycode((XKeyEvent *)&event);
1689 >                                        code = event2keycode(event.xkey);
1690                                  if (code != -1 && code != 0x39) {       // Don't propagate Caps Lock releases
1691                                          ADBKeyUp(code);
1692                                          if (code == 0x36)
# Line 1636 | Line 1700 | static void handle_events(void)
1700                                  if (display_type == DISPLAY_WINDOW) {
1701   #ifdef ENABLE_VOSF
1702                                          if (use_vosf) {                 // VOSF refresh
1703 < #ifdef HAVE_PTHREADS
1640 <                                                pthread_mutex_lock(&Screen_draw_lock);
1641 < #endif
1703 >                                                LOCK_VOSF;
1704                                                  PFLAG_SET_ALL;
1705 < #ifdef HAVE_PTHREADS
1644 <                                                pthread_mutex_unlock(&Screen_draw_lock);
1645 < #endif
1705 >                                                UNLOCK_VOSF;
1706                                                  memset(the_buffer_copy, 0, VideoMonitor.bytes_per_row * VideoMonitor.y);
1707                                          }
1708                                          else
# Line 1658 | Line 1718 | static void handle_events(void)
1718                                  }
1719                                  break;
1720  
1721 <                        case FocusIn:
1722 <                        case FocusOut:
1721 >                        // Window "close" widget clicked
1722 >                        case ClientMessage:
1723 >                                if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) {
1724 >                                        ADBKeyDown(0x7f);       // Power key
1725 >                                        ADBKeyUp(0x7f);
1726 >                                }
1727                                  break;
1728                  }
1729          }
# Line 1879 | Line 1943 | static void update_display_static(void)
1943   *      Screen refresh functions
1944   */
1945  
1946 < // The specialisations hereunder are meant to enable VOSF with DGA in direct
1947 < // addressing mode in case the address spaces (RAM, ROM, FrameBuffer) could
1948 < // not get mapped correctly with respect to the predetermined host frame
1949 < // buffer base address.
1950 < //
1887 < // Hmm, in other words, when in direct addressing mode and DGA is requested,
1888 < // we first try to "triple allocate" the address spaces according to the real
1889 < // host frame buffer address. Then, if it fails, we will use a temporary
1890 < // frame buffer thus making the real host frame buffer updated when pages
1891 < // of the temp frame buffer are altered.
1892 < //
1893 < // As a side effect, a little speed gain in screen updates could be noticed
1894 < // for other modes than DGA.
1895 < //
1896 < // The following two functions below are inline so that a clever compiler
1897 < // could specialise the code according to the current screen depth and
1898 < // display type. A more clever compiler would the job by itself though...
1899 < // (update_display_vosf is inlined as well)
1946 > // We suggest the compiler to inline the next two functions so that it
1947 > // may specialise the code according to the current screen depth and
1948 > // display type. A clever compiler would do that job by itself though...
1949 >
1950 > // NOTE: update_display_vosf is inlined too
1951  
1952   static inline void possibly_quit_dga_mode()
1953   {
# Line 1917 | Line 1968 | static inline void possibly_quit_dga_mod
1968  
1969   static inline void handle_palette_changes(int depth, int display_type)
1970   {
1971 < #ifdef HAVE_PTHREADS
1972 <        pthread_mutex_lock(&palette_lock);
1922 < #endif
1971 >        LOCK_PALETTE;
1972 >
1973          if (palette_changed) {
1974                  palette_changed = false;
1975                  if (depth == 8) {
1976                          XStoreColors(x_display, cmap[0], palette, 256);
1977                          XStoreColors(x_display, cmap[1], palette, 256);
1978 +                        XSync(x_display, false);
1979                                  
1980   #ifdef ENABLE_XF86_DGA
1981                          if (display_type == DISPLAY_DGA) {
# Line 1934 | Line 1985 | static inline void handle_palette_change
1985   #endif
1986                  }
1987          }
1988 < #ifdef HAVE_PTHREADS
1989 <        pthread_mutex_unlock(&palette_lock);
1939 < #endif
1988 >
1989 >        UNLOCK_PALETTE;
1990   }
1991  
1992   static void video_refresh_dga(void)
# Line 1968 | Line 2018 | static void video_refresh_dga_vosf(void)
2018          static int tick_counter = 0;
2019          if (++tick_counter >= frame_skip) {
2020                  tick_counter = 0;
2021 < #ifdef HAVE_PTHREADS
2022 <                pthread_mutex_lock(&Screen_draw_lock);
2023 < #endif
2024 <                update_display_dga_vosf();
2025 < #ifdef HAVE_PTHREADS
1976 <                pthread_mutex_unlock(&Screen_draw_lock);
1977 < #endif
2021 >                if (mainBuffer.dirty) {
2022 >                        LOCK_VOSF;
2023 >                        update_display_dga_vosf();
2024 >                        UNLOCK_VOSF;
2025 >                }
2026          }
2027   }
2028   #endif
# Line 1994 | Line 2042 | static void video_refresh_window_vosf(vo
2042          static int tick_counter = 0;
2043          if (++tick_counter >= frame_skip) {
2044                  tick_counter = 0;
2045 < #ifdef HAVE_PTHREADS
2046 <                pthread_mutex_lock(&Screen_draw_lock);
2047 < #endif
2048 <                update_display_window_vosf();
2049 < #ifdef HAVE_PTHREADS
2050 <                pthread_mutex_unlock(&Screen_draw_lock);
2003 < #endif
2045 >                if (mainBuffer.dirty) {
2046 >                        LOCK_VOSF;
2047 >                        update_display_window_vosf();
2048 >                        UNLOCK_VOSF;
2049 >                        XSync(x_display, false); // Let the server catch up
2050 >                }
2051          }
2052   }
2053   #endif // def ENABLE_VOSF
# Line 2070 | Line 2117 | void VideoRefresh(void)
2117          video_refresh();
2118   }
2119  
2073 #if 0
2074 void VideoRefresh(void)
2075 {
2076 #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA)
2077        // Quit DGA mode if requested
2078        if (quit_full_screen) {
2079                quit_full_screen = false;
2080                if (display_type == DISPLAY_DGA) {
2081 #ifdef ENABLE_XF86_DGA
2082                        XF86DGADirectVideo(x_display, screen, 0);
2083 #endif
2084                        XUngrabPointer(x_display, CurrentTime);
2085                        XUngrabKeyboard(x_display, CurrentTime);
2086                        XUnmapWindow(x_display, the_win);
2087                        XSync(x_display, false);
2088                }
2089        }
2090 #endif
2091
2092        // Handle X events
2093        handle_events();
2094
2095        // Handle palette changes
2096 #ifdef HAVE_PTHREADS
2097        pthread_mutex_lock(&palette_lock);
2098 #endif
2099        if (palette_changed) {
2100                palette_changed = false;
2101                if (depth == 8) {
2102                        XStoreColors(x_display, cmap[0], palette, 256);
2103                        XStoreColors(x_display, cmap[1], palette, 256);
2104                                
2105 #ifdef ENABLE_XF86_DGA
2106                        if (display_type == DISPLAY_DGA) {
2107                                current_dga_cmap ^= 1;
2108                                XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]);
2109                        }
2110 #endif
2111                }
2112        }
2113 #ifdef HAVE_PTHREADS
2114        pthread_mutex_unlock(&palette_lock);
2115 #endif
2116
2117        // In window mode, update display
2118        static int tick_counter = 0;
2119        if (display_type == DISPLAY_WINDOW) {
2120                tick_counter++;
2121                if (frame_skip == 0)
2122                        update_display_dynamic(tick_counter);
2123                else if (tick_counter >= frame_skip) {
2124                        tick_counter = 0;
2125                        update_display_static();
2126                }
2127        }
2128 }
2129 #endif
2130
2120   #ifdef HAVE_PTHREADS
2121   static void *redraw_func(void *arg)
2122   {
# Line 2135 | Line 2124 | static void *redraw_func(void *arg)
2124          int64 ticks = 0;
2125          uint64 next = GetTicks_usec();
2126          while (!redraw_thread_cancel) {
2138 //              VideoRefresh();
2127                  video_refresh();
2128                  next += 16667;
2129                  int64 delay = next - GetTicks_usec();
# Line 2146 | Line 2134 | static void *redraw_func(void *arg)
2134                  ticks++;
2135          }
2136          uint64 end = GetTicks_usec();
2137 <        printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, (end - start) / ticks);
2137 >        // printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start));
2138          return NULL;
2139   }
2140   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines