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.1 by gbeauche, 2000-09-22T17:16:05Z 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-2000 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 < */
30 <
31 < // Align on page boundaries
32 < static uint32 align_on_page_boundary(uint32 size)
33 < {
34 <        const uint32 page_size = getpagesize();
35 <        const uint32 page_mask = page_size - 1;
36 <        return (size + page_mask) & ~page_mask;
37 < }
38 <
39 < // Allocate memory on page boundary
40 < static void * allocate_framebuffer(uint32 size, uint8 * hint = 0)
41 < {
42 <        // Remind that the system can allocate at 0x00000000...
43 <        return mmap((caddr_t)hint, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
44 < }
27 > #include "sigsegv.h"
28 > #include "vm_alloc.h"
29 > #ifdef _WIN32
30 > #include "util_windows.h"
31 > #endif
32  
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 < /*
62 < *      Screen depth identification
49 < */
61 > // Variables for Video on SEGV support
62 > static uint8 *the_host_buffer;  // Host frame buffer in VOSF mode
63  
64 < enum {
65 <        ID_DEPTH_UNKNOWN = -1,
53 <        ID_DEPTH_1,
54 <        ID_DEPTH_8,
55 <        ID_DEPTH_15,
56 <        ID_DEPTH_16,
57 <        ID_DEPTH_24,
58 <        ID_DEPTH_32 = ID_DEPTH_24,
59 <        ID_DEPTH_COUNT
64 > struct ScreenPageInfo {
65 >    int top, bottom;                    // Mapping between this virtual page and Mac scanlines
66   };
67  
68 < static int depth_id(int depth)
69 < {
70 <        int id;
71 <        switch (depth) {
72 <                case 1  : id = ID_DEPTH_1;      break;
73 <                case 8  : id = ID_DEPTH_8;      break;
74 <                case 15 : id = ID_DEPTH_15;     break;
75 <                case 16 : id = ID_DEPTH_16;     break;
76 <                case 24 : id = ID_DEPTH_24;     break;
77 <                case 32 : id = ID_DEPTH_32;     break;
78 <                default : id = ID_DEPTH_UNKNOWN;
79 <        }
74 <        return id;
75 < }
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 < /*
84 < *      Frame buffer copy function templates
85 < */
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 < // No conversion required
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 < #define MEMCPY_PROFITABLE
85 < #ifdef MEMCPY_PROFITABLE
86 < static void do_fbcopy_raw(uint8 * dest, const uint8 * source, uint32 length)
142 > static inline int find_next_page_clear(int page)
143   {
144 <        memcpy(dest, source, length);
145 < }
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 < #error "incomplete"
149 < #define FB_BLIT_1(dst, src)     (dst = (src))
150 < #define FB_BLIT_2(dst, src)     (dst = (src))
151 < #define FB_DEPTH                        8
152 < #define FB_FUNC_NAME            do_fbcopy_raw
96 < #include "video_blit.h"
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 < // RGB 555
174 <
175 < #define FB_BLIT_1(dst, src) \
176 <        (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8))
177 <        
178 < #define FB_BLIT_2(dst, src) \
179 <        (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8))
180 <
181 < #define FB_DEPTH 15
182 < #define FB_FUNC_NAME do_fbcopy_15
110 < #include "video_blit.h"
111 <
112 <
113 < // RGB 565
114 <
115 < #define FB_BLIT_1(dst, src) \
116 <        (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0))
117 <        
118 < #define FB_BLIT_2(dst, src) \
119 <        (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0))
120 <
121 < #define FB_DEPTH 16
122 < #define FB_FUNC_NAME do_fbcopy_16
123 < #include "video_blit.h"
124 <
125 <
126 < // RGB 888
127 <
128 < #define FB_BLIT_1(dst, src) \
129 <        (dst = (src))
130 <
131 < #define FB_BLIT_2(dst, src) \
132 <        (dst = (((src) >> 24) & 0xff) | (((src) >> 16) & 0xff00) | (((src) & 0xff00) << 16) | (((src) & 0xff) << 24))
173 > static int log_base_2(uint32 x)
174 > {
175 >        uint32 mask = 0x80000000;
176 >        int l = 31;
177 >        while (l >= 0 && (x & mask) == 0) {
178 >                mask >>= 1;
179 >                l--;
180 >        }
181 >        return l;
182 > }
183  
184 < #define FB_DEPTH 24
185 < #define FB_FUNC_NAME do_fbcopy_24
186 < #include "video_blit.h"
184 > // Extend size to page boundary
185 > static uint32 page_extend(uint32 size)
186 > {
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  
192  
193   /*
194 < *      Frame buffer copy functions map table
194 > *  Check if VOSF acceleration is profitable on this platform
195   */
196  
197 < typedef void (*fbcopy_func)(uint8 *, const uint8 *, uint32);
198 < static fbcopy_func do_update_framebuffer;
145 <
146 < #define FBCOPY_FUNC(aHandler) do_ ## aHandler
147 <
148 < #if REAL_ADDRESSING || DIRECT_ADDRESSING
149 < #define WD(X) { FBCOPY_FUNC(X), FBCOPY_FUNC(X) }
150 < #else
151 < #define WD(X) { FBCOPY_FUNC(fbcopy_raw), FBCOPY_FUNC(fbcopy_raw) }
152 < #endif
153 <
154 < // fb_copy_funcs[depth_id][native_byte_order][dga_mode]
155 < // NT  : not tested
156 < // OK  : has been successfully tested
157 < // NBO : native byte order
158 < static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
159 < #ifdef WORDS_BIGENDIAN
160 <                                /*      alt byte order    native byte order     */
161 < /*  1 bpp */    {       WD(fbcopy_raw)  , WD(fbcopy_raw)        },      // NT
162 < /*  8 bpp */    {       WD(fbcopy_raw)  , WD(fbcopy_raw)        },      // OK (NBO)
163 < /* 15 bpp */    {       WD(fbcopy_15)   , WD(fbcopy_raw)        },      // NT
164 < /* 16 bpp */    {       WD(fbcopy_16)   , WD(fbcopy_raw)        },      // NT
165 < /* 24 bpp */    {       WD(fbcopy_24)   , WD(fbcopy_raw)        }       // NT
166 < #else
167 < /*  1 bpp */    {       WD(fbcopy_raw)  , WD(fbcopy_raw)        },      // NT
168 < /*  8 bpp */    {       WD(fbcopy_raw)  , WD(fbcopy_raw)        },      // OK (NBO)
169 < /* 15 bpp */    {       WD(fbcopy_15)   , WD(fbcopy_15)         },      // OK (NBO)
170 < /* 16 bpp */    {       WD(fbcopy_16)   , WD(fbcopy_16)         },      // OK (NBO)
171 < /* 24 bpp */    {       WD(fbcopy_24)   , WD(fbcopy_24)         }       // NT
172 < #endif
173 < };
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 < #undef WD
200 > static bool video_vosf_profitable(void)
201 > {
202 >        int64 durations[VOSF_PROFITABLE_TRIES];
203 >        int mean_duration = 0;
204  
205 < #define FBCOPY_FUNC_ERROR \
206 <        ErrorAlert("Invalid screen depth")
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  
221 < #define GET_FBCOPY_FUNC(aDepth, aNativeByteOrder, aDisplay) \
222 <        ((depth_id(aDepth) == ID_DEPTH_UNKNOWN) ? ( FBCOPY_FUNC_ERROR, (fbcopy_func)0 ) : \
223 <        fbcopy_funcs[depth_id(aDepth)][(aNativeByteOrder)][(aDisplay) == DISPLAY_DGA ? 1 : 0])
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  
226  
227   /*
228 < *      Screen fault handler
228 > *  Initialize the VOSF system (mainBuffer structure, SIGSEGV handler)
229   */
230  
231 < static inline void do_handle_screen_fault(unsigned long addr)
231 > static bool video_vosf_init(MONITOR_INIT)
232   {
233 <        if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) {
234 <                fprintf(stderr, "Segmentation fault at 0x%08X\n", addr);
235 <                abort();
233 >        VIDEO_MODE_INIT_MONITOR;
234 >
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 <        const int page  = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
283 <        caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
284 < #ifdef HAVE_PTHREADS
285 <        pthread_mutex_lock(&Screen_draw_lock);
286 < #endif
287 <        PFLAG_SET(page);
288 <        mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
203 < #ifdef HAVE_PTHREADS
204 <        pthread_mutex_unlock(&Screen_draw_lock);
205 < #endif
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 < #if defined(HAVE_SIGINFO_T)
292 < static void Screen_fault_handler(int, siginfo_t * sip, void *)
293 < {
294 <        D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
295 <        do_handle_screen_fault((unsigned long)sip->si_addr);
296 < }
214 < #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
215 < # if defined(__i386__) && defined(__linux__)
216 < static void Screen_fault_handler(int, struct sigcontext scs)
291 >
292 > /*
293 > * Deinitialize VOSF system
294 > */
295 >
296 > static void video_vosf_exit(void)
297   {
298 <        D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
299 <        do_handle_screen_fault((unsigned long)scs.cr2);
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   }
221 # else
222 #  error "No suitable subterfuge for Video on SEGV signals"
223 # endif
224 #else
225 # error "Can't do Video on SEGV signals"
226 #endif
307  
308  
309   /*
310 < *      Screen fault handler initialization
310 > * Screen fault handler
311   */
312  
313 < #if defined(HAVE_SIGINFO_T)
234 < static bool Screen_fault_handler_init()
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_sigaction = Screen_fault_handler;
318 <        vosf_sa.sa_flags = 0;
319 <        return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
320 < }
321 < #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
322 < static bool Screen_fault_handler_init()
323 < {
324 <        // Setup SIGSEGV handler to process writes to frame buffer
325 <        sigemptyset(&vosf_sa.sa_mask);
326 <        vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
327 <        vosf_sa.sa_flags = 0;
328 <        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   }
251 #endif
334  
335  
336   /*
337   *      Update display for Windowed mode and VOSF
338   */
339  
340 < static inline void update_display_window_vosf(void)
340 > /*      How can we deal with array overrun conditions ?
341 >        
342 >        The state of the framebuffer pages that have been touched are maintained
343 >        in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
344 >
345 > Terminology
346 >        
347 >        "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
348 >        "CLEAR Page Guard" refers to the page following the Last Page but is always
349 >        in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
350 >        Page Guard but is always in the SET state.
351 >
352 > Rough process
353 >        
354 >        The update routines must determine which pages have to be blitted to the
355 >        screen. This job consists in finding the first_page that was touched.
356 >        i.e. find the next page that is SET. Then, finding how many pages were
357 >        touched starting from first_page. i.e. find the next page that is CLEAR.
358 >
359 > There are two cases to check:
360 >
361 >        - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
362 >        but it is beyond the valid pageCount value. Therefore, we exit from the
363 >        update routine.
364 >        
365 >        - Last Page is SET: first_page equals (pageCount - 1) and
366 >        find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
367 >        page to the screen. On the next iteration, page equals pageCount and
368 >        find_next_page_set() will reach the SET Page Guard. We still safely exit
369 >        from the update routine because the SET Page Guard position is greater
370 >        than pageCount.
371 > */
372 >
373 > static inline void update_display_window_vosf(VIDEO_DRV_INIT)
374   {
375 +        VIDEO_MODE_INIT;
376 +
377          int page = 0;
378          for (;;) {
379 <                while (PFLAG_ISCLEAR_4(page))
380 <                        page += 4;
264 <                
265 <                while (PFLAG_ISCLEAR(page))
266 <                        page++;
267 <                
268 <                if (page >= mainBuffer.pageCount)
379 >                const unsigned first_page = find_next_page_set(page);
380 >                if (first_page >= mainBuffer.pageCount)
381                          break;
382 <                
383 <                const int first_page = page;
384 <                PFLAG_CLEAR(first_page);
385 <                while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
274 <                        PFLAG_CLEAR(page);
275 <                
382 >
383 >                page = find_next_page_clear(first_page);
384 >                PFLAG_CLEAR_RANGE(first_page, page);
385 >
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, j;
399 <                
400 <                // Check for first column from left and first column
401 <                // from right that have changed
402 <                int x1 = VideoMonitor.x * bytes_per_pixel - 1;
403 <                for (j = y1; j <= y2; j++) {
404 <                        uint8 * const p1 = &the_buffer[j * bytes_per_row];
405 <                        uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
406 <                        for (i = 0; i < x1; i++) {
407 <                                if (p1[i] != p2[i]) {
408 <                                        x1 = i;
299 <                                        break;
300 <                                }
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 + 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 <                x1 /= bytes_per_pixel;
412 <                
413 <                int x2 = x1 * bytes_per_pixel;
414 <                for (j = y2; j >= y1; j--) {
415 <                        uint8 * const p1 = &the_buffer[j * bytes_per_row];
416 <                        uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
417 <                        for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
418 <                                if (p1[i] != p2[i]) {
419 <                                        x2 = i;
420 <                                        break;
421 <                                }
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 + 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 <                x2 /= bytes_per_pixel;
425 <                
426 <                // Update the_host_buffer and copy of the_buffer
427 <                // There is at least one pixel to copy
428 <                const int width = x2 - x1 + 1;
429 <                i = y1 * bytes_per_row + x1 * bytes_per_pixel;
430 <                for (j = y1; j <= y2; j++) {
431 <                        do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
324 <                        memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
325 <                        i += bytes_per_row;
326 <                }
327 <                
328 <                if (have_shm)
329 <                        XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
424 >
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, x1, y1, x1, y1, width, 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          }
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 <                while (PFLAG_ISCLEAR_4(page))
453 <                        page += 4;
348 <                
349 <                while (PFLAG_ISCLEAR(page))
350 <                        page++;
351 <                
352 <                if (page >= mainBuffer.pageCount)
452 >                const unsigned first_page = find_next_page_set(page);
453 >                if (first_page >= mainBuffer.pageCount)
454                          break;
455 <                
456 <                const int first_page = page;
457 <                PFLAG_CLEAR(first_page);
458 <                while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
358 <                        PFLAG_CLEAR(page);
359 <                
455 >
456 >                page = find_next_page_clear(first_page);
457 >                PFLAG_CLEAR_RANGE(first_page, page);
458 >
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 389 | 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 400 | 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++) {
506 <                        do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
506 >                        Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
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   }
514   #endif
515  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines