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.20 by gbeauche, 2001-06-28T22:06:18Z 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 #include <fcntl.h>
28 #include <sys/mman.h>
27   #include "sigsegv.h"
28   #include "vm_alloc.h"
29 + #ifdef _WIN32
30 + #include "util_windows.h"
31 + #endif
32  
33 < #ifdef ENABLE_MON
34 < # include "mon.h"
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
38 static uint32 the_buffer_size;  // Size of allocated the_buffer
63  
64   struct ScreenPageInfo {
65      int top, bottom;                    // Mapping between this virtual page and Mac scanlines
66   };
67  
68   struct ScreenInfo {
45    uintptr memBase;                    // Real start address
69      uintptr memStart;                   // Start address aligned to page boundary
47    uintptr memEnd;                             // Address of one-past-the-end of the screen
70      uint32 memLength;                   // Length of the memory addressed by the screen pages
71      
72 <    uint32 pageSize;                    // Size of a page
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      
# Line 131 | Line 153 | static inline int find_next_page_clear(i
153   #endif
154   }
155  
156 < #ifdef HAVE_PTHREADS
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);
# Line 154 | Line 184 | static int log_base_2(uint32 x)
184   // Extend size to page boundary
185   static uint32 page_extend(uint32 size)
186   {
187 <        const uint32 page_size = getpagesize();
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 < *  Initialize mainBuffer structure
194 > *  Check if VOSF acceleration is profitable on this platform
195   */
196  
197 < static bool video_init_buffer(void)
198 < {
169 <        if (use_vosf) {
170 <                const uint32 page_size  = getpagesize();
171 <                const uint32 page_mask  = page_size - 1;
172 <                
173 <                mainBuffer.memBase      = (uintptr) the_buffer;
174 <                // Round up frame buffer base to page boundary
175 <                mainBuffer.memStart             = (uintptr)((((unsigned long) the_buffer) + page_mask) & ~page_mask);
176 <                mainBuffer.memLength    = the_buffer_size;
177 <                mainBuffer.memEnd       = mainBuffer.memStart + mainBuffer.memLength;
178 <
179 <                mainBuffer.pageSize     = page_size;
180 <                mainBuffer.pageCount    = (mainBuffer.memLength + page_mask)/mainBuffer.pageSize;
181 <                mainBuffer.pageBits     = log_base_2(mainBuffer.pageSize);
182 <
183 <                if (mainBuffer.dirtyPages) {
184 <                        free(mainBuffer.dirtyPages);
185 <                        mainBuffer.dirtyPages = NULL;
186 <                }
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 <                mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2);
200 > static bool video_vosf_profitable(void)
201 > {
202 >        int64 durations[VOSF_PROFITABLE_TRIES];
203 >        int mean_duration = 0;
204  
205 <                if (mainBuffer.pageInfo) {
206 <                        free(mainBuffer.pageInfo);
207 <                        mainBuffer.pageInfo = NULL;
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 <
212 <                mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo));
213 <
197 <                if ((mainBuffer.dirtyPages == 0) || (mainBuffer.pageInfo == 0))
198 <                        return false;
199 <                
200 <                mainBuffer.dirty = false;
211 >                int64 duration = GetTicks_usec() - start;
212 >                mean_duration += duration;
213 >                durations[i] = duration;
214  
215                  PFLAG_CLEAR_ALL;
216 <                // Safety net to insure the loops in the update routines will terminate
204 <                // See "How can we deal with array overrun conditions ?" hereunder for further details
205 <                PFLAG_CLEAR(mainBuffer.pageCount);
206 <                PFLAG_SET(mainBuffer.pageCount+1);
207 <
208 <                uint32 a = 0;
209 <                for (int i = 0; i < mainBuffer.pageCount; i++) {
210 <                        int y1 = a / VideoMonitor.mode.bytes_per_row;
211 <                        if (y1 >= VideoMonitor.mode.y)
212 <                                y1 = VideoMonitor.mode.y - 1;
213 <
214 <                        int y2 = (a + mainBuffer.pageSize) / VideoMonitor.mode.bytes_per_row;
215 <                        if (y2 >= VideoMonitor.mode.y)
216 <                                y2 = VideoMonitor.mode.y - 1;
217 <
218 <                        mainBuffer.pageInfo[i].top = y1;
219 <                        mainBuffer.pageInfo[i].bottom = y2;
220 <
221 <                        a += mainBuffer.pageSize;
222 <                        if (a > mainBuffer.memLength)
223 <                                a = mainBuffer.memLength;
224 <                }
225 <                
226 <                // We can now write-protect the frame buffer
216 >                mainBuffer.dirty = false;
217                  if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0)
218                          return false;
219          }
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 +
226 +
227 + /*
228 + *  Initialize the VOSF system (mainBuffer structure, SIGSEGV handler)
229 + */
230 +
231 + static bool video_vosf_init(MONITOR_INIT)
232 + {
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 +        // 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 + * Deinitialize VOSF system
294 + */
295 +
296 + static void video_vosf_exit(void)
297 + {
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 +
308 +
309 + /*
310   * Screen fault handler
311   */
312  
313 < static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
313 > bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
314   {
240        D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction));
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 ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
322 <                const int page  = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
249 <                caddr_t page_ad = (caddr_t)(addr & -mainBuffer.pageSize);
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 *)page_ad, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE);
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 */
259        fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
260        if (fault_instruction != SIGSEGV_INVALID_PC)
261                fprintf(stderr, " [IP=0x%08X]", fault_instruction);
262        fprintf(stderr, "\n");
263 #if EMULATED_68K
264        uaecptr nextpc;
265        extern void m68k_dumpstate(uaecptr *nextpc);
266        m68k_dumpstate(&nextpc);
267 #endif
268 #ifdef ENABLE_MON
269        char *arg[4] = {"mon", "-m", "-r", NULL};
270        mon(3, arg);
271        QuitEmulator();
272 #endif
332          return false;
333   }
334  
# Line 278 | Line 337 | static bool screen_fault_handler(sigsegv
337   *      Update display for Windowed mode and VOSF
338   */
339  
281 // From video_blit.cpp
282 extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
283 extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
284
340   /*      How can we deal with array overrun conditions ?
341          
342          The state of the framebuffer pages that have been touched are maintained
# Line 315 | 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 335 | Line 392 | static inline void update_display_window
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.mode.bytes_per_row;
397 <                const int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.x;
398 <                int i = y1 * bytes_per_row, j;
342 <                
343 <                if (VideoMonitor.mode.depth == VDEPTH_1BIT) {
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.mode.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.mode.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.mode.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.mode.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          }
436          mainBuffer.dirty = false;
437   }
# Line 374 | Line 445 | static inline void update_display_window
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 392 | Line 465 | static inline void update_display_dga_vo
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.mode.bytes_per_row;
469 <                const int bytes_per_pixel = VideoMonitor.mode.bytes_per_row / VideoMonitor.mode.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.mode.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 415 | 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.mode.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 426 | 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 433 | 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