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.2 by gbeauche, 2002-04-21T11:47:18Z vs.
Revision 1.7 by gbeauche, 2003-12-04T22:29:15Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines