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

Comparing SheepShaver/src/Unix/video_x.cpp (file contents):
Revision 1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.6 by gbeauche, 2003-11-21T17:01:33Z

# Line 18 | Line 18
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  
21 + #include "sysdeps.h"
22 +
23   #include <X11/Xlib.h>
24   #include <X11/Xutil.h>
25   #include <X11/keysym.h>
26   #include <X11/extensions/XShm.h>
27   #include <sys/ipc.h>
28   #include <sys/shm.h>
29 < #include <pthread.h>
29 > #include <errno.h>
30 >
31 > #ifdef HAVE_PTHREADS
32 > # include <pthread.h>
33 > #endif
34 >
35 > #ifdef ENABLE_XF86_DGA
36 > #include <X11/extensions/xf86dga.h>
37 > #endif
38 >
39 > #ifdef ENABLE_XF86_VIDMODE
40 > # include <X11/extensions/xf86vmode.h>
41 > #endif
42  
29 #include "sysdeps.h"
43   #include "main.h"
44   #include "adb.h"
45   #include "prefs.h"
# Line 38 | Line 51
51   #define DEBUG 0
52   #include "debug.h"
53  
41 #ifdef ENABLE_XF86_DGA
42 #include <X11/extensions/xf86dga.h>
43 #endif
44
45 #ifdef ENABLE_XF86_VIDMODE
46 #include <X11/extensions/xf86vmode.h>
47 #endif
54  
55 + // Constants
56 + const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
57  
58   // Global variables
59   static int32 frame_skip;
60   static bool redraw_thread_active = false;       // Flag: Redraw thread installed
61   static pthread_t redraw_thread;                         // Redraw thread
62  
63 + static bool local_X11;                                          // Flag: X server running on local machine?
64   static volatile bool thread_stop_req = false;
65   static volatile bool thread_stop_ack = false;   // Acknowledge for thread_stop_req
66  
67   static bool has_dga = false;                            // Flag: Video DGA capable
68   static bool has_vidmode = false;                        // Flag: VidMode extension available
69  
70 + #ifdef ENABLE_VOSF
71 + static bool use_vosf = true;                            // Flag: VOSF enabled
72 + #else
73 + static const bool use_vosf = false;                     // VOSF not possible
74 + #endif
75 +
76   static bool palette_changed = false;            // Flag: Palette changed, redraw thread must update palette
77   static bool ctrl_down = false;                          // Flag: Ctrl key pressed
78   static bool quit_full_screen = false;           // Flag: DGA close requested from redraw thread
# Line 67 | Line 82 | static bool emerg_quit = false;                                // Fl
82   static bool emul_suspended = false;                     // Flag: emulator suspended
83   static Window suspend_win;                                      // "Suspend" window
84   static void *fb_save = NULL;                            // Saved frame buffer for suspend
85 + static bool use_keycodes = false;                       // Flag: Use keycodes rather than keysyms
86 + static int keycode_table[256];                          // X keycode -> Mac keycode translation table
87  
88   // X11 variables
89   static int screen;                                                      // Screen number
# Line 92 | Line 109 | static Cursor mac_cursor;
109   static GC cursor_gc, cursor_mask_gc;
110   static bool cursor_changed = false;                     // Flag: Cursor changed, window_func must update cursor
111   static bool have_shm = false;                           // Flag: SHM present and usable
112 < static uint8 *the_buffer;                                       // Pointer to Mac frame buffer
112 > static uint8 *the_buffer = NULL;                        // Pointer to Mac frame buffer
113   static uint8 *the_buffer_copy = NULL;           // Copy of Mac frame buffer
114 + static uint32 the_buffer_size;                          // Size of allocated the_buffer
115  
116   // Variables for DGA mode
117   static char *dga_screen_base;
# Line 111 | Line 129 | static int num_x_video_modes;
129   static void *redraw_func(void *arg);
130  
131  
132 < // From main_linux.cpp
132 > // From main_unix.cpp
133 > extern char *x_display_name;
134   extern Display *x_display;
135  
136   // From sys_unix.cpp
137   extern void SysMountFirstFloppy(void);
138  
139  
140 + // Video acceleration through SIGSEGV
141 + #ifdef ENABLE_VOSF
142 + # include "video_vosf.h"
143 + #endif
144 +
145 +
146   /*
147   *  Open display (window or fullscreen)
148   */
# Line 138 | Line 163 | static int error_handler(Display *d, XEr
163   // Open window
164   static bool open_window(int width, int height)
165   {
166 +        int aligned_width = (width + 15) & ~15;
167 +        int aligned_height = (height + 15) & ~15;
168 +
169          // Set absolute mouse mode
170          ADBSetRelMouseMode(false);
171  
# Line 179 | Line 207 | static bool open_window(int width, int h
207                  XFree((char *)hints);
208          }
209  
210 +        // 1-bit mode is big-endian; if the X server is little-endian, we can't
211 +        // use SHM because that doesn't allow changing the image byte order
212 +        bool need_msb_image = (depth == 1 && XImageByteOrder(x_display) == LSBFirst);
213 +
214          // Try to create and attach SHM image
215          have_shm = false;
216 <        if (depth != 1 && XShmQueryExtension(x_display)) {
216 >        if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) {
217  
218                  // Create SHM image ("height + 2" for safety)
219 <                img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
219 >                img = XShmCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height);
220                  shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777);
221 <                screen_base = (uint32)shmat(shminfo.shmid, 0, 0);
222 <                the_buffer = (uint8 *)screen_base;
191 <                shminfo.shmaddr = img->data = (char *)screen_base;
221 >                the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0);
222 >                shminfo.shmaddr = img->data = (char *)the_buffer_copy;
223                  shminfo.readOnly = False;
224  
225                  // Try to attach SHM image, catching errors
# Line 209 | Line 240 | static bool open_window(int width, int h
240  
241          // Create normal X image if SHM doesn't work ("height + 2" for safety)
242          if (!have_shm) {
243 <                int bytes_per_row = width;
243 >                int bytes_per_row = aligned_width;
244                  switch (depth) {
245                          case 1:
246                                  bytes_per_row /= 8;
# Line 223 | Line 254 | static bool open_window(int width, int h
254                                  bytes_per_row *= 4;
255                                  break;
256                  }
257 <                screen_base = (uint32)malloc((height + 2) * bytes_per_row);
258 <                the_buffer = (uint8 *)screen_base;
228 <                img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)screen_base, width, height, 32, bytes_per_row);
257 >                the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row);
258 >                img = XCreateImage(x_display, vis, depth == 1 ? 1 : xdepth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row);
259          }
260  
261          // 1-Bit mode is big-endian
# Line 234 | Line 264 | static bool open_window(int width, int h
264          img->bitmap_bit_order = MSBFirst;
265      }
266  
267 <        // Allocate memory for frame buffer copy
268 <        the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line);
267 > #ifdef ENABLE_VOSF
268 >        use_vosf = true;
269 >        // Allocate memory for frame buffer (SIZE is extended to page-boundary)
270 >        the_host_buffer = the_buffer_copy;
271 >        the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line);
272 >        the_buffer = (uint8 *)vm_acquire(the_buffer_size);
273 >        the_buffer_copy = (uint8 *)malloc(the_buffer_size);
274 >        D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
275 > #else
276 >        // Allocate memory for frame buffer
277 >        the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line);
278 >        D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
279 > #endif
280 >        screen_base = (uint32)the_buffer;
281  
282          // Create GC
283          the_gc = XCreateGC(x_display, the_win, 0, 0);
# Line 255 | Line 297 | static bool open_window(int width, int h
297          mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0);
298          cursor_changed = false;
299  
300 +        // Init blitting routines
301 +        bool native_byte_order;
302 + #ifdef WORDS_BIGENDIAN
303 +        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
304 + #else
305 +        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
306 + #endif
307 + #ifdef ENABLE_VOSF
308 +        Screen_blitter_init(&visualInfo, native_byte_order, depth);
309 + #endif
310 +
311          // Set bytes per row
312          VModes[cur_mode].viRowBytes = img->bytes_per_line;
313          XSync(x_display, false);
# Line 289 | Line 342 | static bool open_dga(int width, int heig
342          XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
343          XF86DGASetViewPort(x_display, screen, 0, 0);
344          XF86DGASetVidPage(x_display, screen, 0);
292        screen_base = (uint32)dga_screen_base;
345  
346          // Set colormap
347          if (depth == 8)
# Line 307 | Line 359 | static bool open_dga(int width, int heig
359                          bytes_per_row *= 4;
360                          break;
361          }
362 +
363 + #if ENABLE_VOSF
364 +        bool native_byte_order;
365 + #ifdef WORDS_BIGENDIAN
366 +        native_byte_order = (XImageByteOrder(x_display) == MSBFirst);
367 + #else
368 +        native_byte_order = (XImageByteOrder(x_display) == LSBFirst);
369 + #endif
370 + #if REAL_ADDRESSING || DIRECT_ADDRESSING
371 +        // Screen_blitter_init() returns TRUE if VOSF is mandatory
372 +        // i.e. the framebuffer update function is not Blit_Copy_Raw
373 +        use_vosf = Screen_blitter_init(&visualInfo, native_byte_order, depth);
374 +        
375 +        if (use_vosf) {
376 +          // Allocate memory for frame buffer (SIZE is extended to page-boundary)
377 +          the_host_buffer = the_buffer;
378 +          the_buffer_size = page_extend((height + 2) * bytes_per_row);
379 +          the_buffer_copy = (uint8 *)malloc(the_buffer_size);
380 +          the_buffer = (uint8 *)vm_acquire(the_buffer_size);
381 +        }
382 + #else
383 +        use_vosf = false;
384 +        the_buffer = dga_screen_base;
385 + #endif
386 + #endif
387 +        screen_base = (uint32)the_buffer;
388 +
389          VModes[cur_mode].viRowBytes = bytes_per_row;
390          XSync(x_display, false);
391          return true;
# Line 333 | Line 412 | static bool open_display(void)
412                          depth = 8;
413                          break;
414                  case APPLE_16_BIT:
415 <                        depth = 16;
415 >                        depth = xdepth == 15 ? 15 : 16;
416                          break;
417                  case APPLE_32_BIT:
418                          depth = 32;
419                          break;
420          }
421 +
422 +        bool display_open = false;
423          if (display_type == DIS_SCREEN)
424 <                return open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
424 >                display_open = open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
425          else if (display_type == DIS_WINDOW)
426 <                return open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
427 <        else
428 <                return false;
426 >                display_open = open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize);
427 >
428 > #ifdef ENABLE_VOSF
429 >        if (use_vosf) {
430 >                // Initialize the VOSF system
431 >                if (!video_vosf_init()) {
432 >                        ErrorAlert(GetString(STR_VOSF_INIT_ERR));
433 >                        return false;
434 >                }
435 >        }
436 > #endif
437 >        
438 >        return display_open;
439   }
440  
441  
# Line 355 | Line 446 | static bool open_display(void)
446   // Close window
447   static void close_window(void)
448   {
449 +        if (have_shm) {
450 +                XShmDetach(x_display, &shminfo);
451 + #ifdef ENABLE_VOSF
452 +                the_host_buffer = NULL; // don't free() in driver_base dtor
453 + #else
454 +                the_buffer_copy = NULL; // don't free() in driver_base dtor
455 + #endif
456 +        }
457 +        if (img) {
458 +                if (!have_shm)
459 +                        img->data = NULL;
460 +                XDestroyImage(img);
461 +        }
462 +        if (have_shm) {
463 +                shmdt(shminfo.shmaddr);
464 +                shmctl(shminfo.shmid, IPC_RMID, 0);
465 +        }
466 +        if (the_gc)
467 +                XFreeGC(x_display, the_gc);
468 +
469          // Close window
470          XDestroyWindow(x_display, the_win);
360
361        // Close frame buffer copy
362        if (the_buffer_copy) {
363                free(the_buffer_copy);
364                the_buffer_copy = NULL;
365        }
471   }
472  
473   // Close DGA mode
# Line 378 | Line 483 | static void close_dga(void)
483          if (has_vidmode)
484                  XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]);
485   #endif
486 +
487 +        if (!use_vosf) {
488 +                // don't free() the screen buffer in driver_base dtor
489 +                the_buffer = NULL;
490 +        }
491 + #ifdef ENABLE_VOSF
492 +        else {
493 +                // don't free() the screen buffer in driver_base dtor
494 +                the_host_buffer = NULL;
495 +        }
496 + #endif
497   }
498  
499   static void close_display(void)
# Line 386 | Line 502 | static void close_display(void)
502                  close_dga();
503          else if (display_type == DIS_WINDOW)
504                  close_window();
505 +
506 + #ifdef ENABLE_VOSF
507 +        if (use_vosf) {
508 +                // Deinitialize VOSF
509 +                video_vosf_exit();
510 +        }
511 + #endif
512 +
513 +        // Free frame buffer(s)
514 +        if (!use_vosf) {
515 +                if (the_buffer_copy) {
516 +                        free(the_buffer_copy);
517 +                        the_buffer_copy = NULL;
518 +                }
519 +        }
520 + #ifdef ENABLE_VOSF
521 +        else {
522 +                // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will
523 +                if (the_buffer != VM_MAP_FAILED) {
524 +                        D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
525 +                        vm_release(the_buffer, the_buffer_size);
526 +                        the_buffer = NULL;
527 +                }
528 +                if (the_host_buffer) {
529 +                        D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
530 +                        free(the_host_buffer);
531 +                        the_host_buffer = NULL;
532 +                }
533 +                if (the_buffer_copy) {
534 +                        D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
535 +                        free(the_buffer_copy);
536 +                        the_buffer_copy = NULL;
537 +                }
538 +        }
539 + #endif
540   }
541  
542  
# Line 393 | Line 544 | static void close_display(void)
544   *  Initialization
545   */
546  
547 + // Init keycode translation table
548 + static void keycode_init(void)
549 + {
550 +        bool use_kc = PrefsFindBool("keycodes");
551 +        if (use_kc) {
552 +
553 +                // Get keycode file path from preferences
554 +                const char *kc_path = PrefsFindString("keycodefile");
555 +
556 +                // Open keycode table
557 +                FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r");
558 +                if (f == NULL) {
559 +                        char str[256];
560 +                        sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno));
561 +                        WarningAlert(str);
562 +                        return;
563 +                }
564 +
565 +                // Default translation table
566 +                for (int i=0; i<256; i++)
567 +                        keycode_table[i] = -1;
568 +
569 +                // Search for server vendor string, then read keycodes
570 +                const char *vendor = ServerVendor(x_display);
571 +                bool vendor_found = false;
572 +                char line[256];
573 +                while (fgets(line, 255, f)) {
574 +                        // Read line
575 +                        int len = strlen(line);
576 +                        if (len == 0)
577 +                                continue;
578 +                        line[len-1] = 0;
579 +
580 +                        // Comments begin with "#" or ";"
581 +                        if (line[0] == '#' || line[0] == ';' || line[0] == 0)
582 +                                continue;
583 +
584 +                        if (vendor_found) {
585 +                                // Read keycode
586 +                                int x_code, mac_code;
587 +                                if (sscanf(line, "%d %d", &x_code, &mac_code) == 2)
588 +                                        keycode_table[x_code & 0xff] = mac_code;
589 +                                else
590 +                                        break;
591 +                        } else {
592 +                                // Search for vendor string
593 +                                if (strstr(vendor, line) == vendor)
594 +                                        vendor_found = true;
595 +                        }
596 +                }
597 +
598 +                // Keycode file completely read
599 +                fclose(f);
600 +                use_keycodes = vendor_found;
601 +
602 +                // Vendor not found? Then display warning
603 +                if (!vendor_found) {
604 +                        char str[256];
605 +                        sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME);
606 +                        WarningAlert(str);
607 +                        return;
608 +                }
609 +        }
610 + }
611 +
612   static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type)
613   {
614          if (allow & test) {
# Line 456 | Line 672 | static bool has_mode(int x, int y)
672  
673   bool VideoInit(void)
674   {
675 + #ifdef ENABLE_VOSF
676 +        // Zero the mainBuffer structure
677 +        mainBuffer.dirtyPages = NULL;
678 +        mainBuffer.pageInfo = NULL;
679 + #endif
680 +        
681 +        // Check if X server runs on local machine
682 +        local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0)
683 +                 || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0);
684 +    
685 +        // Init keycode translation
686 +        keycode_init();
687 +
688          // Init variables
689          private_data = NULL;
690          cur_mode = 0;   // Window 640x480
# Line 471 | Line 700 | bool VideoInit(void)
700   #ifdef ENABLE_XF86_DGA
701          // DGA available?
702      int event_base, error_base;
703 <    if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
703 >    if (local_X11 && XF86DGAQueryExtension(x_display, &event_base, &error_base)) {
704                  int dga_flags = 0;
705                  XF86DGAQueryDirectVideo(x_display, screen, &dga_flags);
706                  has_dga = dga_flags & XF86DGADirectPresent;
# Line 652 | Line 881 | void VideoExit(void)
881                  redraw_thread_active = false;
882          }
883  
884 + #ifdef ENABLE_VOSF
885 +        if (use_vosf) {
886 +                // Deinitialize VOSF
887 +                video_vosf_exit();
888 +        }
889 + #endif
890 +
891          // Close window and server connection
892          if (x_display != NULL) {
893                  XSync(x_display, false);
# Line 729 | Line 965 | static void resume_emul(void)
965          XF86DGASetViewPort(x_display, screen, 0, 0);
966          XSync(x_display, false);
967  
968 +        // the_buffer already contains the data to restore. i.e. since a temporary
969 +        // frame buffer is used when VOSF is actually used, fb_save is therefore
970 +        // not necessary.
971 + #ifdef ENABLE_VOSF
972 +        if (use_vosf) {
973 +                LOCK_VOSF;
974 +                PFLAG_SET_ALL;
975 +                UNLOCK_VOSF;
976 +                memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
977 +        }
978 + #endif
979 +        
980          // Restore frame buffer
981          if (fb_save) {
982 + #ifdef ENABLE_VOSF
983 +                // Don't copy fb_save to the temporary frame buffer in VOSF mode
984 +                if (!use_vosf)
985 + #endif
986                  memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes);
987                  free(fb_save);
988                  fb_save = NULL;
# Line 904 | Line 1156 | static int kc_decode(KeySym ks)
1156          return -1;
1157   }
1158  
1159 < static int event2keycode(XKeyEvent *ev)
1159 > static int event2keycode(XKeyEvent &ev)
1160   {
1161          KeySym ks;
1162          int as;
1163          int i = 0;
1164  
1165          do {
1166 <                ks = XLookupKeysym(ev, i++);
1166 >                ks = XLookupKeysym(&ev, i++);
1167                  as = kc_decode(ks);
1168                  if (as != -1)
1169                          return as;
# Line 954 | Line 1206 | static void handle_events(void)
1206  
1207                          // Keyboard
1208                          case KeyPress: {
1209 <                                int code;
1210 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1209 >                                int code = event2keycode(event.xkey);
1210 >                                if (use_keycodes && code != -1)
1211 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1212 >                                if (code != -1) {
1213                                          if (!emul_suspended) {
1214                                                  ADBKeyDown(code);
1215                                                  if (code == 0x36)
# Line 968 | Line 1222 | static void handle_events(void)
1222                                  break;
1223                          }
1224                          case KeyRelease: {
1225 <                                int code;
1226 <                                if ((code = event2keycode((XKeyEvent *)&event)) != -1) {
1225 >                                int code = event2keycode(event.xkey);
1226 >                                if (use_keycodes && code != 1)
1227 >                                        code = keycode_table[event.xkey.keycode & 0xff];
1228 >                                if (code != -1) {
1229                                          ADBKeyUp(code);
1230                                          if (code == 0x36)
1231                                                  ctrl_down = false;
# Line 979 | Line 1235 | static void handle_events(void)
1235  
1236                          // Hidden parts exposed, force complete refresh
1237                          case Expose:
1238 + #ifdef ENABLE_VOSF
1239 +                                if (use_vosf) {                 // VOSF refresh
1240 +                                        LOCK_VOSF;
1241 +                                        PFLAG_SET_ALL;
1242 +                                        UNLOCK_VOSF;
1243 +                                }
1244 + #endif
1245                                  memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize);
1246                                  break;
1247                  }
# Line 1376 | Line 1639 | static void *redraw_func(void *arg)
1639                                  tick_counter = 0;
1640  
1641                                  // Update display
1642 <                                update_display();
1642 > #ifdef ENABLE_VOSF
1643 >                                if (use_vosf) {
1644 >                                        if (mainBuffer.dirty) {
1645 >                                                LOCK_VOSF;
1646 >                                                update_display_window_vosf();
1647 >                                                UNLOCK_VOSF;
1648 >                                                XSync(x_display, false); // Let the server catch up
1649 >                                        }
1650 >                                }
1651 >                                else
1652 > #endif
1653 >                                        update_display();
1654  
1655                                  // Set new cursor image if it was changed
1656                                  if (cursor_changed) {
# Line 1391 | Line 1665 | static void *redraw_func(void *arg)
1665                                  }
1666                          }
1667                  }
1668 + #ifdef ENABLE_VOSF
1669 +                else if (use_vosf) {
1670 +                        // Update display (VOSF variant)
1671 +                        static int tick_counter = 0;
1672 +                        if (++tick_counter >= frame_skip) {
1673 +                                tick_counter = 0;
1674 +                                if (mainBuffer.dirty) {
1675 +                                        LOCK_VOSF;
1676 +                                        update_display_dga_vosf();
1677 +                                        UNLOCK_VOSF;
1678 +                                }
1679 +                        }
1680 +                }
1681 + #endif
1682  
1683                  // Set new palette if it was changed
1684                  if (palette_changed && !emul_suspended) {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines