home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / video_vosf.h < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-20  |  7.7 KB  |  243 lines

  1. /*
  2.  *  video_vosf.h - Video/graphics emulation, video on SEGV signals support
  3.  *
  4.  *  Basilisk II (C) 1997-2001 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
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #ifndef VIDEO_VOSF_H
  22. #define VIDEO_VOSF_H
  23.  
  24. // Note: this file is #include'd in video_x.cpp
  25. #ifdef ENABLE_VOSF
  26.  
  27. /*
  28.  *  Page-aligned memory allocation
  29.  */
  30.  
  31. // Align on page boundaries
  32. static uintptr align_on_page_boundary(uintptr 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. }
  45.  
  46. // Screen fault handler
  47. static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
  48. {
  49.     D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction));
  50.     const uintptr addr = (uintptr)fault_address;
  51.     
  52.     /* Someone attempted to write to the frame buffer. Make it writeable
  53.      * now so that the data could actually be written. It will be made
  54.      * read-only back in one of the screen update_*() functions.
  55.      */
  56.     if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
  57.         const int page  = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
  58.         caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
  59.         LOCK_VOSF;
  60.         PFLAG_SET(page);
  61.         mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
  62.         mainBuffer.dirty = true;
  63.         UNLOCK_VOSF;
  64.         return true;
  65.     }
  66.     
  67.     /* Otherwise, we don't know how to handle the fault, let it crash */
  68.     fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
  69.     if (fault_instruction != SIGSEGV_INVALID_PC)
  70.         fprintf(stderr, " [IP=0x%08X]", fault_instruction);
  71.     fprintf(stderr, "\n");
  72.     return false;
  73. }
  74.  
  75. /*
  76.  *    Update display for Windowed mode and VOSF
  77.  */
  78.  
  79. // From video_blit.cpp
  80. extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
  81. extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
  82.  
  83. /*    How can we deal with array overrun conditions ?
  84.     
  85.     The state of the framebuffer pages that have been touched are maintained
  86.     in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
  87.  
  88. Terminology
  89.     
  90.     "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
  91.     "CLEAR Page Guard" refers to the page following the Last Page but is always
  92.     in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
  93.     Page Guard but is always in the SET state.
  94.  
  95. Rough process
  96.     
  97.     The update routines must determine which pages have to be blitted to the
  98.     screen. This job consists in finding the first_page that was touched.
  99.     i.e. find the next page that is SET. Then, finding how many pages were
  100.     touched starting from first_page. i.e. find the next page that is CLEAR.
  101.  
  102. There are two cases to check:
  103.  
  104.     - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
  105.     but it is beyond the valid pageCount value. Therefore, we exit from the
  106.     update routine.
  107.     
  108.     - Last Page is SET: first_page equals (pageCount - 1) and
  109.     find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
  110.     page to the screen. On the next iteration, page equals pageCount and
  111.     find_next_page_set() will reach the SET Page Guard. We still safely exit
  112.     from the update routine because the SET Page Guard position is greater
  113.     than pageCount.
  114. */
  115.  
  116. static inline void update_display_window_vosf(void)
  117. {
  118.     int page = 0;
  119.     for (;;) {
  120.         const int first_page = find_next_page_set(page);
  121.         if (first_page >= mainBuffer.pageCount)
  122.             break;
  123.  
  124.         page = find_next_page_clear(first_page);
  125.         PFLAG_CLEAR_RANGE(first_page, page);
  126.  
  127.         // Make the dirty pages read-only again
  128.         const int32 offset  = first_page << mainBuffer.pageBits;
  129.         const uint32 length = (page - first_page) << mainBuffer.pageBits;
  130.         mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
  131.         
  132.         // There is at least one line to update
  133.         const int y1 = mainBuffer.pageInfo[first_page].top;
  134.         const int y2 = mainBuffer.pageInfo[page - 1].bottom;
  135.         const int height = y2 - y1 + 1;
  136.         
  137.         const int bytes_per_row = VideoMonitor.bytes_per_row;
  138.         const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
  139.         int i = y1 * bytes_per_row, j;
  140.         
  141.         if (depth == 1) {
  142.  
  143.             // Update the_host_buffer and copy of the_buffer
  144.             for (j = y1; j <= y2; j++) {
  145.                 Screen_blit(the_host_buffer + i, the_buffer + i, VideoMonitor.x >> 3);
  146.                 i += bytes_per_row;
  147.             }
  148.  
  149.         } else {
  150.  
  151.             // Update the_host_buffer and copy of the_buffer
  152.             for (j = y1; j <= y2; j++) {
  153.                 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * VideoMonitor.x);
  154.                 i += bytes_per_row;
  155.             }
  156.         }
  157.  
  158.         if (have_shm)
  159.             XShmPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height, 0);
  160.         else
  161.             XPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height);
  162.     }
  163.  
  164.     mainBuffer.dirty = false;
  165. }
  166.  
  167.  
  168. /*
  169.  *    Update display for DGA mode and VOSF
  170.  *    (only in Direct Addressing mode)
  171.  */
  172.  
  173. #if REAL_ADDRESSING || DIRECT_ADDRESSING
  174. static inline void update_display_dga_vosf(void)
  175. {
  176.     int page = 0;
  177.     for (;;) {
  178.         const int first_page = find_next_page_set(page);
  179.         if (first_page >= mainBuffer.pageCount)
  180.             break;
  181.  
  182.         page = find_next_page_clear(first_page);
  183.         PFLAG_CLEAR_RANGE(first_page, page);
  184.  
  185.         // Make the dirty pages read-only again
  186.         const int32 offset  = first_page << mainBuffer.pageBits;
  187.         const uint32 length = (page - first_page) << mainBuffer.pageBits;
  188.         mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
  189.         
  190.         // I am sure that y2 >= y1 and depth != 1
  191.         const int y1 = mainBuffer.pageInfo[first_page].top;
  192.         const int y2 = mainBuffer.pageInfo[page - 1].bottom;
  193.         
  194.         const int bytes_per_row = VideoMonitor.bytes_per_row;
  195.         const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
  196.         int i, j;
  197.         
  198.         // Check for first column from left and first column
  199.         // from right that have changed
  200.         int x1 = VideoMonitor.x * bytes_per_pixel - 1;
  201.         for (j = y1; j <= y2; j++) {
  202.             uint8 * const p1 = &the_buffer[j * bytes_per_row];
  203.             uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
  204.             for (i = 0; i < x1; i++) {
  205.                 if (p1[i] != p2[i]) {
  206.                     x1 = i;
  207.                     break;
  208.                 }
  209.             }
  210.         }
  211.         x1 /= bytes_per_pixel;
  212.         
  213.         int x2 = x1 * bytes_per_pixel;
  214.         for (j = y2; j >= y1; j--) {
  215.             uint8 * const p1 = &the_buffer[j * bytes_per_row];
  216.             uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
  217.             for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
  218.                 if (p1[i] != p2[i]) {
  219.                     x2 = i;
  220.                     break;
  221.                 }
  222.             }
  223.         }
  224.         x2 /= bytes_per_pixel;
  225.         
  226.         // Update the_host_buffer and copy of the_buffer
  227.         // There should be at least one pixel to copy
  228.         const int width = x2 - x1 + 1;
  229.         i = y1 * bytes_per_row + x1 * bytes_per_pixel;
  230.         for (j = y1; j <= y2; j++) {
  231.             Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
  232.             memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
  233.             i += bytes_per_row;
  234.         }
  235.     }
  236.     mainBuffer.dirty = false;
  237. }
  238. #endif
  239.  
  240. #endif /* ENABLE_VOSF */
  241.  
  242. #endif /* VIDEO_VOSF_H */
  243.