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, 5 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

# Content
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 // Extend size to page boundary
32 static uint32 page_extend(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 // Screen fault handler
40 static bool screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
41 {
42 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 /* 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 caddr_t page_ad = (caddr_t)(addr & -mainBuffer.pageSize);
52 LOCK_VOSF;
53 PFLAG_SET(page);
54 vm_protect((char *)page_ad, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE);
55 mainBuffer.dirty = true;
56 UNLOCK_VOSF;
57 return true;
58 }
59
60 /* 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 if (fault_instruction != SIGSEGV_INVALID_PC)
63 fprintf(stderr, " [IP=0x%08X]", fault_instruction);
64 fprintf(stderr, "\n");
65 return false;
66 }
67
68 /*
69 * Update display for Windowed mode and VOSF
70 */
71
72 // 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 /* 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 The update routines must determine which pages have to be blitted to the
91 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 There are two cases to check:
96
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 static inline void update_display_window_vosf(void)
110 {
111 int page = 0;
112 for (;;) {
113 const int first_page = find_next_page_set(page);
114 if (first_page >= mainBuffer.pageCount)
115 break;
116
117 page = find_next_page_clear(first_page);
118 PFLAG_CLEAR_RANGE(first_page, page);
119
120 // 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 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
124
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 int i = y1 * bytes_per_row, j;
133
134 if (depth == 1) {
135
136 // Update the_host_buffer and copy of the_buffer
137 for (j = y1; j <= y2; j++) {
138 Screen_blit(the_host_buffer + i, the_buffer + i, VideoMonitor.x >> 3);
139 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 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * VideoMonitor.x);
147 i += bytes_per_row;
148 }
149 }
150
151 if (have_shm)
152 XShmPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height, 0);
153 else
154 XPutImage(x_display, the_win, the_gc, img, 0, y1, 0, y1, VideoMonitor.x, height);
155 }
156
157 mainBuffer.dirty = false;
158 }
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 const int first_page = find_next_page_set(page);
172 if (first_page >= mainBuffer.pageCount)
173 break;
174
175 page = find_next_page_clear(first_page);
176 PFLAG_CLEAR_RANGE(first_page, page);
177
178 // 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 vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ);
182
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 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
225 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
226 i += bytes_per_row;
227 }
228 }
229 mainBuffer.dirty = false;
230 }
231 #endif
232
233 #endif /* ENABLE_VOSF */
234
235 #endif /* VIDEO_VOSF_H */