ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.17
Committed: 2001-06-26T22:35:41Z (23 years, 4 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.16: +6 -13 lines
Log Message:
- added SIGSEGV support for Linux/Alpha (to be checked), Darwin/PPC
- added uniform virtual memory allocation
  (supports mmap(), vm_allocate(), or fallbacks to malloc()/free())
- cleaned up memory allocation in main_unix.cpp

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * video_vosf.h - Video/graphics emulation, video on SEGV signals support
3     *
4 gbeauche 1.13 * Basilisk II (C) 1997-2001 Christian Bauer
5 gbeauche 1.1 *
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 gbeauche 1.17 // Extend size to page boundary
32     static uint32 page_extend(uint32 size)
33 gbeauche 1.1 {
34     const uint32 page_size = getpagesize();
35     const uint32 page_mask = page_size - 1;
36     return (size + page_mask) & ~page_mask;
37     }
38    
39 gbeauche 1.16 // Screen fault handler
40     static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
41 gbeauche 1.1 {
42 gbeauche 1.16 D(bug("screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", fault_address, fault_instruction));
43     const uintptr addr = (uintptr)fault_address;
44    
45 gbeauche 1.11 /* Someone attempted to write to the frame buffer. Make it writeable
46     * now so that the data could actually be written. It will be made
47     * read-only back in one of the screen update_*() functions.
48     */
49     if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
50     const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
51 gbeauche 1.17 caddr_t page_ad = (caddr_t)(addr & -mainBuffer.pageSize);
52 gbeauche 1.11 LOCK_VOSF;
53     PFLAG_SET(page);
54 gbeauche 1.17 vm_protect((char *)page_ad, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE);
55 gbeauche 1.13 mainBuffer.dirty = true;
56 gbeauche 1.11 UNLOCK_VOSF;
57 gbeauche 1.16 return true;
58 gbeauche 1.1 }
59    
60 gbeauche 1.11 /* Otherwise, we don't know how to handle the fault, let it crash */
61     fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
62 gbeauche 1.16 if (fault_instruction != SIGSEGV_INVALID_PC)
63     fprintf(stderr, " [IP=0x%08X]", fault_instruction);
64 gbeauche 1.11 fprintf(stderr, "\n");
65 gbeauche 1.16 return false;
66 gbeauche 1.1 }
67    
68     /*
69     * Update display for Windowed mode and VOSF
70     */
71    
72 gbeauche 1.13 // From video_blit.cpp
73     extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
74     extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
75    
76 gbeauche 1.12 /* How can we deal with array overrun conditions ?
77    
78     The state of the framebuffer pages that have been touched are maintained
79     in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
80    
81     Terminology
82    
83     "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
84     "CLEAR Page Guard" refers to the page following the Last Page but is always
85     in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
86     Page Guard but is always in the SET state.
87    
88     Rough process
89    
90 gbeauche 1.13 The update routines must determine which pages have to be blitted to the
91 gbeauche 1.12 screen. This job consists in finding the first_page that was touched.
92     i.e. find the next page that is SET. Then, finding how many pages were
93     touched starting from first_page. i.e. find the next page that is CLEAR.
94    
95 gbeauche 1.13 There are two cases to check:
96 gbeauche 1.12
97     - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
98     but it is beyond the valid pageCount value. Therefore, we exit from the
99     update routine.
100    
101     - Last Page is SET: first_page equals (pageCount - 1) and
102     find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
103     page to the screen. On the next iteration, page equals pageCount and
104     find_next_page_set() will reach the SET Page Guard. We still safely exit
105     from the update routine because the SET Page Guard position is greater
106     than pageCount.
107     */
108    
109 gbeauche 1.1 static inline void update_display_window_vosf(void)
110     {
111     int page = 0;
112     for (;;) {
113 gbeauche 1.11 const int first_page = find_next_page_set(page);
114     if (first_page >= mainBuffer.pageCount)
115 gbeauche 1.1 break;
116 gbeauche 1.11
117     page = find_next_page_clear(first_page);
118     PFLAG_CLEAR_RANGE(first_page, page);
119 cebix 1.7
120 gbeauche 1.1 // Make the dirty pages read-only again
121     const int32 offset = first_page << mainBuffer.pageBits;
122     const uint32 length = (page - first_page) << mainBuffer.pageBits;
123 gbeauche 1.17 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
124 gbeauche 1.1
125     // There is at least one line to update
126     const int y1 = mainBuffer.pageInfo[first_page].top;
127     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
128     const int height = y2 - y1 + 1;
129    
130     const int bytes_per_row = VideoMonitor.bytes_per_row;
131     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
132 cebix 1.15 int i = y1 * bytes_per_row, j;
133 gbeauche 1.1
134 cebix 1.6 if (depth == 1) {
135    
136     // Update the_host_buffer and copy of the_buffer
137     for (j = y1; j <= y2; j++) {
138 cebix 1.15 Screen_blit(the_host_buffer + i, the_buffer + i, VideoMonitor.x >> 3);
139 cebix 1.6 i += bytes_per_row;
140     }
141    
142     } else {
143    
144     // Update the_host_buffer and copy of the_buffer
145     for (j = y1; j <= y2; j++) {
146 cebix 1.15 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * VideoMonitor.x);
147 cebix 1.6 i += bytes_per_row;
148     }
149 gbeauche 1.1 }
150 cebix 1.15
151 gbeauche 1.1 if (have_shm)
152 cebix 1.15 XShmPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height, 0);
153 gbeauche 1.1 else
154 cebix 1.15 XPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height);
155 gbeauche 1.1 }
156 cebix 1.15
157 gbeauche 1.13 mainBuffer.dirty = false;
158 gbeauche 1.1 }
159    
160    
161     /*
162     * Update display for DGA mode and VOSF
163     * (only in Direct Addressing mode)
164     */
165    
166     #if REAL_ADDRESSING || DIRECT_ADDRESSING
167     static inline void update_display_dga_vosf(void)
168     {
169     int page = 0;
170     for (;;) {
171 gbeauche 1.11 const int first_page = find_next_page_set(page);
172     if (first_page >= mainBuffer.pageCount)
173 gbeauche 1.1 break;
174 gbeauche 1.11
175     page = find_next_page_clear(first_page);
176     PFLAG_CLEAR_RANGE(first_page, page);
177    
178 gbeauche 1.1 // Make the dirty pages read-only again
179     const int32 offset = first_page << mainBuffer.pageBits;
180     const uint32 length = (page - first_page) << mainBuffer.pageBits;
181 gbeauche 1.17 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
182 gbeauche 1.1
183     // I am sure that y2 >= y1 and depth != 1
184     const int y1 = mainBuffer.pageInfo[first_page].top;
185     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
186    
187     const int bytes_per_row = VideoMonitor.bytes_per_row;
188     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
189     int i, j;
190    
191     // Check for first column from left and first column
192     // from right that have changed
193     int x1 = VideoMonitor.x * bytes_per_pixel - 1;
194     for (j = y1; j <= y2; j++) {
195     uint8 * const p1 = &the_buffer[j * bytes_per_row];
196     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
197     for (i = 0; i < x1; i++) {
198     if (p1[i] != p2[i]) {
199     x1 = i;
200     break;
201     }
202     }
203     }
204     x1 /= bytes_per_pixel;
205    
206     int x2 = x1 * bytes_per_pixel;
207     for (j = y2; j >= y1; j--) {
208     uint8 * const p1 = &the_buffer[j * bytes_per_row];
209     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
210     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
211     if (p1[i] != p2[i]) {
212     x2 = i;
213     break;
214     }
215     }
216     }
217     x2 /= bytes_per_pixel;
218    
219     // Update the_host_buffer and copy of the_buffer
220     // There should be at least one pixel to copy
221     const int width = x2 - x1 + 1;
222     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
223     for (j = y1; j <= y2; j++) {
224 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
225 gbeauche 1.1 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
226     i += bytes_per_row;
227     }
228     }
229 gbeauche 1.13 mainBuffer.dirty = false;
230 gbeauche 1.1 }
231     #endif
232    
233     #endif /* ENABLE_VOSF */
234    
235     #endif /* VIDEO_VOSF_H */