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

Comparing BasiliskII/src/Unix/video_vosf.h (file contents):
Revision 1.15 by cebix, 2001-03-06T18:41:12Z vs.
Revision 1.46 by gbeauche, 2004-12-11T10:20:32Z

# Line 1 | Line 1
1   /*
2   *  video_vosf.h - Video/graphics emulation, video on SEGV signals support
3   *
4 < *  Basilisk II (C) 1997-2001 Christian Bauer
4 > *  Basilisk II (C) 1997-2004 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 21 | Line 21
21   #ifndef VIDEO_VOSF_H
22   #define VIDEO_VOSF_H
23  
24 < // Note: this file is #include'd in video_x.cpp
24 > // Note: this file must be #include'd only in video_x.cpp
25   #ifdef ENABLE_VOSF
26  
27 < /*
28 < *  Page-aligned memory allocation
29 < */
27 > #include "sigsegv.h"
28 > #include "vm_alloc.h"
29 > #ifdef _WIN32
30 > #include "util_windows.h"
31 > #endif
32  
33 < // Align on page boundaries
34 < static uintptr align_on_page_boundary(uintptr size)
35 < {
36 <        const uint32 page_size = getpagesize();
37 <        const uint32 page_mask = page_size - 1;
38 <        return (size + page_mask) & ~page_mask;
33 > // Glue for SDL and X11 support
34 > #ifdef USE_SDL_VIDEO
35 > #define MONITOR_INIT                    SDL_monitor_desc &monitor
36 > #define VIDEO_DRV_INIT                  driver_window *drv
37 > #define VIDEO_DRV_ROW_BYTES             drv->s->pitch
38 > #define VIDEO_DRV_LOCK_PIXELS   if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s)
39 > #define VIDEO_DRV_UNLOCK_PIXELS if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s)
40 > #else
41 > #ifdef SHEEPSHAVER
42 > #define MONITOR_INIT                    /* nothing */
43 > #define VIDEO_DRV_INIT                  /* nothing */
44 > #define VIDEO_DRV_WINDOW                the_win
45 > #define VIDEO_DRV_GC                    the_gc
46 > #define VIDEO_DRV_IMAGE                 img
47 > #define VIDEO_DRV_HAVE_SHM              have_shm
48 > #else
49 > #define MONITOR_INIT                    X11_monitor_desc &monitor
50 > #define VIDEO_DRV_INIT                  driver_window *drv
51 > #define VIDEO_DRV_WINDOW                drv->w
52 > #define VIDEO_DRV_GC                    drv->gc
53 > #define VIDEO_DRV_IMAGE                 drv->img
54 > #define VIDEO_DRV_HAVE_SHM              drv->have_shm
55 > #endif
56 > #define VIDEO_DRV_LOCK_PIXELS   /* nothing */
57 > #define VIDEO_DRV_UNLOCK_PIXELS /* nothing */
58 > #define VIDEO_DRV_ROW_BYTES             VIDEO_DRV_IMAGE->bytes_per_line
59 > #endif
60 >
61 > // Variables for Video on SEGV support
62 > static uint8 *the_host_buffer;  // Host frame buffer in VOSF mode
63 >
64 > struct ScreenPageInfo {
65 >    int top, bottom;                    // Mapping between this virtual page and Mac scanlines
66 > };
67 >
68 > struct ScreenInfo {
69 >    uintptr memStart;                   // Start address aligned to page boundary
70 >    uint32 memLength;                   // Length of the memory addressed by the screen pages
71 >    
72 >    uintptr pageSize;                   // Size of a page
73 >    int pageBits;                               // Shift count to get the page number
74 >    uint32 pageCount;                   // Number of pages allocated to the screen
75 >    
76 >        bool dirty;                                     // Flag: set if the frame buffer was touched
77 >    char * dirtyPages;                  // Table of flags set if page was altered
78 >    ScreenPageInfo * pageInfo;  // Table of mappings page -> Mac scanlines
79 > };
80 >
81 > static ScreenInfo mainBuffer;
82 >
83 > #define PFLAG_SET_VALUE                 0x00
84 > #define PFLAG_CLEAR_VALUE               0x01
85 > #define PFLAG_SET_VALUE_4               0x00000000
86 > #define PFLAG_CLEAR_VALUE_4             0x01010101
87 > #define PFLAG_SET(page)                 mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE
88 > #define PFLAG_CLEAR(page)               mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE
89 > #define PFLAG_ISSET(page)               (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE)
90 > #define PFLAG_ISCLEAR(page)             (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE)
91 >
92 > #ifdef UNALIGNED_PROFITABLE
93 > # define PFLAG_ISSET_4(page)    (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4)
94 > # define PFLAG_ISCLEAR_4(page)  (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4)
95 > #else
96 > # define PFLAG_ISSET_4(page) \
97 >                PFLAG_ISSET(page  ) && PFLAG_ISSET(page+1) \
98 >        &&      PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3)
99 > # define PFLAG_ISCLEAR_4(page) \
100 >                PFLAG_ISCLEAR(page  ) && PFLAG_ISCLEAR(page+1) \
101 >        &&      PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3)
102 > #endif
103 >
104 > // Set the selected page range [ first_page, last_page [ into the SET state
105 > #define PFLAG_SET_RANGE(first_page, last_page) \
106 >        memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \
107 >                (last_page) - (first_page))
108 >
109 > // Set the selected page range [ first_page, last_page [ into the CLEAR state
110 > #define PFLAG_CLEAR_RANGE(first_page, last_page) \
111 >        memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \
112 >                (last_page) - (first_page))
113 >
114 > #define PFLAG_SET_ALL do { \
115 >        PFLAG_SET_RANGE(0, mainBuffer.pageCount); \
116 >        mainBuffer.dirty = true; \
117 > } while (0)
118 >
119 > #define PFLAG_CLEAR_ALL do { \
120 >        PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \
121 >        mainBuffer.dirty = false; \
122 > } while (0)
123 >
124 > // Set the following macro definition to 1 if your system
125 > // provides a really fast strchr() implementation
126 > //#define HAVE_FAST_STRCHR 0
127 >
128 > static inline int find_next_page_set(int page)
129 > {
130 > #if HAVE_FAST_STRCHR
131 >        char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE);
132 >        return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
133 > #else
134 >        while (PFLAG_ISCLEAR_4(page))
135 >                page += 4;
136 >        while (PFLAG_ISCLEAR(page))
137 >                page++;
138 >        return page;
139 > #endif
140   }
141  
142 < // Allocate memory on page boundary
40 < static void * allocate_framebuffer(uint32 size, uint8 * hint = 0)
142 > static inline int find_next_page_clear(int page)
143   {
144 <        // Remind that the system can allocate at 0x00000000...
145 <        return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
144 > #if HAVE_FAST_STRCHR
145 >        char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE);
146 >        return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount;
147 > #else
148 >        while (PFLAG_ISSET_4(page))
149 >                page += 4;
150 >        while (PFLAG_ISSET(page))
151 >                page++;
152 >        return page;
153 > #endif
154   }
155  
156 + #ifdef HAVE_SPINLOCKS
157 + static spinlock_t vosf_lock = SPIN_LOCK_UNLOCKED;                               // Mutex to protect frame buffer (dirtyPages in fact)
158 + #define LOCK_VOSF spin_lock(&vosf_lock)
159 + #define UNLOCK_VOSF spin_unlock(&vosf_lock)
160 + #elif defined(_WIN32)
161 + static mutex_t vosf_lock;                                                                               // Mutex to protect frame buffer (dirtyPages in fact)
162 + #define LOCK_VOSF vosf_lock.lock();
163 + #define UNLOCK_VOSF vosf_lock.unlock();
164 + #elif defined(HAVE_PTHREADS)
165 + static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER;   // Mutex to protect frame buffer (dirtyPages in fact)
166 + #define LOCK_VOSF pthread_mutex_lock(&vosf_lock);
167 + #define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock);
168 + #else
169 + #define LOCK_VOSF
170 + #define UNLOCK_VOSF
171 + #endif
172  
173 < /*
48 < *      Screen fault handler
49 < */
50 <
51 < const uintptr INVALID_PC = (uintptr)-1;
52 <
53 < static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
173 > static int log_base_2(uint32 x)
174   {
175 <        /* Someone attempted to write to the frame buffer. Make it writeable
176 <         * now so that the data could actually be written. It will be made
177 <         * read-only back in one of the screen update_*() functions.
178 <         */
179 <        if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
60 <                const int page  = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
61 <                caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
62 <                LOCK_VOSF;
63 <                PFLAG_SET(page);
64 <                mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
65 <                mainBuffer.dirty = true;
66 <                UNLOCK_VOSF;
67 <                return;
175 >        uint32 mask = 0x80000000;
176 >        int l = 31;
177 >        while (l >= 0 && (x & mask) == 0) {
178 >                mask >>= 1;
179 >                l--;
180          }
181 <        
70 <        /* Otherwise, we don't know how to handle the fault, let it crash */
71 <        fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
72 <        if (pc != INVALID_PC)
73 <                fprintf(stderr, " [IP=0x%08X]", pc);
74 <        fprintf(stderr, "\n");
75 <        
76 <        signal(SIGSEGV, SIG_DFL);
181 >        return l;
182   }
183  
184 < #if defined(HAVE_SIGINFO_T)
185 <
81 < static void Screen_fault_handler(int, siginfo_t * sip, void *)
184 > // Extend size to page boundary
185 > static uint32 page_extend(uint32 size)
186   {
187 <        D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
188 <        do_handle_screen_fault((uintptr)sip->si_addr);
187 >        const uint32 page_size = vm_page_size();
188 >        const uint32 page_mask = page_size - 1;
189 >        return (size + page_mask) & ~page_mask;
190   }
191  
87 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
192  
193 < # if defined(__i386__) && defined(__linux__)
194 < static void Screen_fault_handler(int, struct sigcontext scs)
195 < {
92 <        D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
93 <        do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
94 < }
193 > /*
194 > *  Check if VOSF acceleration is profitable on this platform
195 > */
196  
197 < # elif defined(__m68k__) && defined(__NetBSD__)
197 > const int VOSF_PROFITABLE_TRIES = 3;                    // Make 3 attempts for full screen update
198 > const int VOSF_PROFITABLE_THRESHOLD = 16667;    // 60 Hz
199  
200 < # include <m68k/frame.h>
99 < static void Screen_fault_handler(int, int code, struct sigcontext *scp)
200 > static bool video_vosf_profitable(void)
201   {
202 <        D(bug("Screen_fault_handler: ADDR=0x%08X\n", code));
203 <        struct sigstate {
204 <                int ss_flags;
205 <                struct frame ss_frame;
206 <        };
207 <        struct sigstate *state = (struct sigstate *)scp->sc_ap;
208 <        uintptr fault_addr;
209 <        switch (state->ss_frame.f_format) {
210 <                case 7:         // 68040 access error
211 <                        // "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown
212 <                        fault_addr = state->ss_frame.f_fmt7.f_fa;
213 <                        break;
214 <                default:
215 <                        fault_addr = (uintptr)code;
216 <                        break;
202 >        int64 durations[VOSF_PROFITABLE_TRIES];
203 >        int mean_duration = 0;
204 >
205 >        for (int i = 0; i < VOSF_PROFITABLE_TRIES; i++) {
206 >                uint64 start = GetTicks_usec();
207 >                for (int p = 0; p < mainBuffer.pageCount; p++) {
208 >                        uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize));
209 >                        addr[0] = 0; // Trigger Screen_fault_handler()
210 >                }
211 >                int64 duration = GetTicks_usec() - start;
212 >                mean_duration += duration;
213 >                durations[i] = duration;
214 >
215 >                PFLAG_CLEAR_ALL;
216 >                mainBuffer.dirty = false;
217 >                if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
218 >                        return false;
219          }
220 <        do_handle_screen_fault(fault_addr);
220 >
221 >        mean_duration /= VOSF_PROFITABLE_TRIES;
222 >        D(bug("Triggered %d screen faults in %ld usec on average\n", mainBuffer.pageCount, mean_duration));
223 >        return (mean_duration < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1)));
224   }
225  
120 # elif defined(__powerpc__) && defined(__linux__)
226  
227 < static void Screen_fault_handler(int, struct sigcontext_struct *scs)
227 > /*
228 > *  Initialize the VOSF system (mainBuffer structure, SIGSEGV handler)
229 > */
230 >
231 > static bool video_vosf_init(MONITOR_INIT)
232   {
233 <        D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs->regs->dar, scs->regs->nip));
125 <        do_handle_screen_fault((uintptr)scs->regs->dar, (uintptr)scs->regs->nip);
126 < }
233 >        VIDEO_MODE_INIT_MONITOR;
234  
235 < # else
236 < #  error "No suitable subterfuge for Video on SEGV signals"
237 < # endif
238 < #else
239 < # error "Can't do Video on SEGV signals"
240 < #endif
235 >        const uintptr page_size = vm_page_size();
236 >        const uintptr page_mask = page_size - 1;
237 >        
238 >        // Round up frame buffer base to page boundary
239 >        mainBuffer.memStart = (((uintptr) the_buffer) + page_mask) & ~page_mask;
240 >        
241 >        // The frame buffer size shall already be aligned to page boundary (use page_extend)
242 >        mainBuffer.memLength = the_buffer_size;
243 >        
244 >        mainBuffer.pageSize = page_size;
245 >        mainBuffer.pageBits = log_base_2(mainBuffer.pageSize);
246 >        mainBuffer.pageCount =  (mainBuffer.memLength + page_mask)/mainBuffer.pageSize;
247 >        
248 >        // The "2" more bytes requested are a safety net to insure the
249 >        // loops in the update routines will terminate.
250 >        // See "How can we deal with array overrun conditions ?" hereunder for further details.
251 >        mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2);
252 >        if (mainBuffer.dirtyPages == NULL)
253 >                return false;
254 >                
255 >        PFLAG_CLEAR_ALL;
256 >        PFLAG_CLEAR(mainBuffer.pageCount);
257 >        PFLAG_SET(mainBuffer.pageCount+1);
258 >        
259 >        // Allocate and fill in pageInfo with start and end (inclusive) row in number of bytes
260 >        mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo));
261 >        if (mainBuffer.pageInfo == NULL)
262 >                return false;
263 >        
264 >        uint32 a = 0;
265 >        for (unsigned i = 0; i < mainBuffer.pageCount; i++) {
266 >                unsigned y1 = a / VIDEO_MODE_ROW_BYTES;
267 >                if (y1 >= VIDEO_MODE_Y)
268 >                        y1 = VIDEO_MODE_Y - 1;
269 >
270 >                unsigned y2 = (a + mainBuffer.pageSize) / VIDEO_MODE_ROW_BYTES;
271 >                if (y2 >= VIDEO_MODE_Y)
272 >                        y2 = VIDEO_MODE_Y - 1;
273 >
274 >                mainBuffer.pageInfo[i].top = y1;
275 >                mainBuffer.pageInfo[i].bottom = y2;
276 >
277 >                a += mainBuffer.pageSize;
278 >                if (a > mainBuffer.memLength)
279 >                        a = mainBuffer.memLength;
280 >        }
281 >        
282 >        // We can now write-protect the frame buffer
283 >        if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
284 >                return false;
285 >        
286 >        // The frame buffer is sane, i.e. there is no write to it yet
287 >        mainBuffer.dirty = false;
288 >        return true;
289 > }
290  
291  
292   /*
293 < *      Screen fault handler initialization
293 > * Deinitialize VOSF system
294   */
295  
296 < #if defined(HAVE_SIGINFO_T)
141 < static bool Screen_fault_handler_init()
296 > static void video_vosf_exit(void)
297   {
298 <        // Setup SIGSEGV handler to process writes to frame buffer
299 <        sigemptyset(&vosf_sa.sa_mask);
300 <        vosf_sa.sa_sigaction = Screen_fault_handler;
301 <        vosf_sa.sa_flags = SA_SIGINFO;
302 <        return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
298 >        if (mainBuffer.pageInfo) {
299 >                free(mainBuffer.pageInfo);
300 >                mainBuffer.pageInfo = NULL;
301 >        }
302 >        if (mainBuffer.dirtyPages) {
303 >                free(mainBuffer.dirtyPages);
304 >                mainBuffer.dirtyPages = NULL;
305 >        }
306   }
307 < #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
308 < static bool Screen_fault_handler_init()
307 >
308 >
309 > /*
310 > * Screen fault handler
311 > */
312 >
313 > bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
314   {
315 <        // Setup SIGSEGV handler to process writes to frame buffer
316 <        sigemptyset(&vosf_sa.sa_mask);
317 <        vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
318 < #if !EMULATED_68K && defined(__NetBSD__)
319 <        sigaddset(&vosf_sa.sa_mask, SIGALRM);
320 <        vosf_sa.sa_flags = SA_ONSTACK;
321 < #else
322 <        vosf_sa.sa_flags = 0;
323 < #endif
324 <        return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
315 >        const uintptr addr = (uintptr)fault_address;
316 >        
317 >        /* Someone attempted to write to the frame buffer. Make it writeable
318 >         * now so that the data could actually be written to. It will be made
319 >         * read-only back in one of the screen update_*() functions.
320 >         */
321 >        if (((uintptr)addr - mainBuffer.memStart) < mainBuffer.memLength) {
322 >                const int page  = ((uintptr)addr - mainBuffer.memStart) >> mainBuffer.pageBits;
323 >                LOCK_VOSF;
324 >                PFLAG_SET(page);
325 >                vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE);
326 >                mainBuffer.dirty = true;
327 >                UNLOCK_VOSF;
328 >                return true;
329 >        }
330 >        
331 >        /* Otherwise, we don't know how to handle the fault, let it crash */
332 >        return false;
333   }
163 #endif
334  
335  
336   /*
337   *      Update display for Windowed mode and VOSF
338   */
339  
170 // From video_blit.cpp
171 extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
172 extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
173
340   /*      How can we deal with array overrun conditions ?
341          
342          The state of the framebuffer pages that have been touched are maintained
# Line 204 | Line 370 | There are two cases to check:
370          than pageCount.
371   */
372  
373 < static inline void update_display_window_vosf(void)
373 > static inline void update_display_window_vosf(VIDEO_DRV_INIT)
374   {
375 +        VIDEO_MODE_INIT;
376 +
377          int page = 0;
378          for (;;) {
379 <                const int first_page = find_next_page_set(page);
379 >                const unsigned first_page = find_next_page_set(page);
380                  if (first_page >= mainBuffer.pageCount)
381                          break;
382  
# Line 218 | Line 386 | static inline void update_display_window
386                  // Make the dirty pages read-only again
387                  const int32 offset  = first_page << mainBuffer.pageBits;
388                  const uint32 length = (page - first_page) << mainBuffer.pageBits;
389 <                mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
389 >                vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
390                  
391                  // There is at least one line to update
392                  const int y1 = mainBuffer.pageInfo[first_page].top;
393                  const int y2 = mainBuffer.pageInfo[page - 1].bottom;
394                  const int height = y2 - y1 + 1;
395 <                
396 <                const int bytes_per_row = VideoMonitor.bytes_per_row;
397 <                const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
398 <                int i = y1 * bytes_per_row, j;
231 <                
232 <                if (depth == 1) {
395 >
396 >                VIDEO_DRV_LOCK_PIXELS;
397 >
398 >                if ((int)VIDEO_MODE_DEPTH < VIDEO_DEPTH_8BIT) {
399  
400                          // Update the_host_buffer and copy of the_buffer
401 +                        const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
402 +                        const int dst_bytes_per_row = VIDEO_DRV_ROW_BYTES;
403 +                        const int pixels_per_byte = VIDEO_MODE_X / src_bytes_per_row;
404 +                        int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
405                          for (j = y1; j <= y2; j++) {
406 <                                Screen_blit(the_host_buffer + i, the_buffer + i, VideoMonitor.x >> 3);
407 <                                i += bytes_per_row;
406 >                                Screen_blit(the_host_buffer + i2, the_buffer + i1, VIDEO_MODE_X / pixels_per_byte);
407 >                                i1 += src_bytes_per_row;
408 >                                i2 += dst_bytes_per_row;
409                          }
410  
411                  } else {
412  
413                          // Update the_host_buffer and copy of the_buffer
414 +                        const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES;
415 +                        const int dst_bytes_per_row = VIDEO_DRV_ROW_BYTES;
416 +                        const int bytes_per_pixel = src_bytes_per_row / VIDEO_MODE_X;
417 +                        int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j;
418                          for (j = y1; j <= y2; j++) {
419 <                                Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * VideoMonitor.x);
420 <                                i += bytes_per_row;
419 >                                Screen_blit(the_host_buffer + i2, the_buffer + i1, bytes_per_pixel * VIDEO_MODE_X);
420 >                                i1 += src_bytes_per_row;
421 >                                i2 += dst_bytes_per_row;
422                          }
423                  }
424  
425 <                if (have_shm)
426 <                        XShmPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height, 0);
425 >                VIDEO_DRV_UNLOCK_PIXELS;
426 >
427 > #ifdef USE_SDL_VIDEO
428 >                SDL_UpdateRect(drv->s, 0, y1, VIDEO_MODE_X, height);
429 > #else
430 >                if (VIDEO_DRV_HAVE_SHM)
431 >                        XShmPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height, 0);
432                  else
433 <                        XPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height);
433 >                        XPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height);
434 > #endif
435          }
254
436          mainBuffer.dirty = false;
437   }
438  
439  
440   /*
441   *      Update display for DGA mode and VOSF
442 < *      (only in Direct Addressing mode)
442 > *      (only in Real or Direct Addressing mode)
443   */
444  
445   #if REAL_ADDRESSING || DIRECT_ADDRESSING
446   static inline void update_display_dga_vosf(void)
447   {
448 +        VIDEO_MODE_INIT;
449 +
450          int page = 0;
451          for (;;) {
452 <                const int first_page = find_next_page_set(page);
452 >                const unsigned first_page = find_next_page_set(page);
453                  if (first_page >= mainBuffer.pageCount)
454                          break;
455  
# Line 276 | Line 459 | static inline void update_display_dga_vo
459                  // Make the dirty pages read-only again
460                  const int32 offset  = first_page << mainBuffer.pageBits;
461                  const uint32 length = (page - first_page) << mainBuffer.pageBits;
462 <                mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
462 >                vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
463                  
464                  // I am sure that y2 >= y1 and depth != 1
465                  const int y1 = mainBuffer.pageInfo[first_page].top;
466                  const int y2 = mainBuffer.pageInfo[page - 1].bottom;
467                  
468 <                const int bytes_per_row = VideoMonitor.bytes_per_row;
469 <                const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
468 >                const int bytes_per_row = VIDEO_MODE_ROW_BYTES;
469 >                const int bytes_per_pixel = VIDEO_MODE_ROW_BYTES / VIDEO_MODE_X;
470                  int i, j;
471                  
472                  // Check for first column from left and first column
473                  // from right that have changed
474 <                int x1 = VideoMonitor.x * bytes_per_pixel - 1;
474 >                int x1 = VIDEO_MODE_X * bytes_per_pixel - 1;
475                  for (j = y1; j <= y2; j++) {
476                          uint8 * const p1 = &the_buffer[j * bytes_per_row];
477                          uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
# Line 305 | Line 488 | static inline void update_display_dga_vo
488                  for (j = y2; j >= y1; j--) {
489                          uint8 * const p1 = &the_buffer[j * bytes_per_row];
490                          uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
491 <                        for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
491 >                        for (i = VIDEO_MODE_X * bytes_per_pixel - 1; i > x2; i--) {
492                                  if (p1[i] != p2[i]) {
493                                          x2 = i;
494                                          break;
# Line 316 | Line 499 | static inline void update_display_dga_vo
499                  
500                  // Update the_host_buffer and copy of the_buffer
501                  // There should be at least one pixel to copy
502 +                VIDEO_DRV_LOCK_PIXELS;
503                  const int width = x2 - x1 + 1;
504                  i = y1 * bytes_per_row + x1 * bytes_per_pixel;
505                  for (j = y1; j <= y2; j++) {
# Line 323 | Line 507 | static inline void update_display_dga_vo
507                          memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
508                          i += bytes_per_row;
509                  }
510 +                VIDEO_DRV_UNLOCK_PIXELS;
511          }
512          mainBuffer.dirty = false;
513   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines