ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.14
Committed: 2001-02-10T15:29:01Z (23 years, 4 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: snapshot-17022001
Changes since 1.13: +8 -0 lines
Log Message:
implemented VOSF on Linux/ppc

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 // 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
47 /*
48 * Screen fault handler
49 */
50
51 const uintptr INVALID_PC = (uintptr)-1;
52
53 static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
54 {
55 /* Someone attempted to write to the frame buffer. Make it writeable
56 * now so that the data could actually be written. It will be made
57 * read-only back in one of the screen update_*() functions.
58 */
59 if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
60 const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
61 caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
62 LOCK_VOSF;
63 PFLAG_SET(page);
64 mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
65 mainBuffer.dirty = true;
66 UNLOCK_VOSF;
67 return;
68 }
69
70 /* Otherwise, we don't know how to handle the fault, let it crash */
71 fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
72 if (pc != INVALID_PC)
73 fprintf(stderr, " [IP=0x%08X]", pc);
74 fprintf(stderr, "\n");
75
76 signal(SIGSEGV, SIG_DFL);
77 }
78
79 #if defined(HAVE_SIGINFO_T)
80
81 static void Screen_fault_handler(int, siginfo_t * sip, void *)
82 {
83 D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
84 do_handle_screen_fault((uintptr)sip->si_addr);
85 }
86
87 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
88
89 # if defined(__i386__) && defined(__linux__)
90 static void Screen_fault_handler(int, struct sigcontext scs)
91 {
92 D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
93 do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
94 }
95
96 # elif defined(__m68k__) && defined(__NetBSD__)
97
98 # include <m68k/frame.h>
99 static void Screen_fault_handler(int, int code, struct sigcontext *scp)
100 {
101 D(bug("Screen_fault_handler: ADDR=0x%08X\n", code));
102 struct sigstate {
103 int ss_flags;
104 struct frame ss_frame;
105 };
106 struct sigstate *state = (struct sigstate *)scp->sc_ap;
107 uintptr fault_addr;
108 switch (state->ss_frame.f_format) {
109 case 7: // 68040 access error
110 // "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown
111 fault_addr = state->ss_frame.f_fmt7.f_fa;
112 break;
113 default:
114 fault_addr = (uintptr)code;
115 break;
116 }
117 do_handle_screen_fault(fault_addr);
118 }
119
120 # elif defined(__powerpc__) && defined(__linux__)
121
122 static void Screen_fault_handler(int, struct sigcontext_struct *scs)
123 {
124 D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs->regs->dar, scs->regs->nip));
125 do_handle_screen_fault((uintptr)scs->regs->dar, (uintptr)scs->regs->nip);
126 }
127
128 # else
129 # error "No suitable subterfuge for Video on SEGV signals"
130 # endif
131 #else
132 # error "Can't do Video on SEGV signals"
133 #endif
134
135
136 /*
137 * Screen fault handler initialization
138 */
139
140 #if defined(HAVE_SIGINFO_T)
141 static bool Screen_fault_handler_init()
142 {
143 // Setup SIGSEGV handler to process writes to frame buffer
144 sigemptyset(&vosf_sa.sa_mask);
145 vosf_sa.sa_sigaction = Screen_fault_handler;
146 vosf_sa.sa_flags = SA_SIGINFO;
147 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
148 }
149 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
150 static bool Screen_fault_handler_init()
151 {
152 // Setup SIGSEGV handler to process writes to frame buffer
153 sigemptyset(&vosf_sa.sa_mask);
154 vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
155 #if !EMULATED_68K && defined(__NetBSD__)
156 sigaddset(&vosf_sa.sa_mask, SIGALRM);
157 vosf_sa.sa_flags = SA_ONSTACK;
158 #else
159 vosf_sa.sa_flags = 0;
160 #endif
161 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
162 }
163 #endif
164
165
166 /*
167 * Update display for Windowed mode and VOSF
168 */
169
170 // From video_blit.cpp
171 extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
172 extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
173
174 /* How can we deal with array overrun conditions ?
175
176 The state of the framebuffer pages that have been touched are maintained
177 in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
178
179 Terminology
180
181 "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
182 "CLEAR Page Guard" refers to the page following the Last Page but is always
183 in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
184 Page Guard but is always in the SET state.
185
186 Rough process
187
188 The update routines must determine which pages have to be blitted to the
189 screen. This job consists in finding the first_page that was touched.
190 i.e. find the next page that is SET. Then, finding how many pages were
191 touched starting from first_page. i.e. find the next page that is CLEAR.
192
193 There are two cases to check:
194
195 - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
196 but it is beyond the valid pageCount value. Therefore, we exit from the
197 update routine.
198
199 - Last Page is SET: first_page equals (pageCount - 1) and
200 find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
201 page to the screen. On the next iteration, page equals pageCount and
202 find_next_page_set() will reach the SET Page Guard. We still safely exit
203 from the update routine because the SET Page Guard position is greater
204 than pageCount.
205 */
206
207 static inline void update_display_window_vosf(void)
208 {
209 int page = 0;
210 for (;;) {
211 const int first_page = find_next_page_set(page);
212 if (first_page >= mainBuffer.pageCount)
213 break;
214
215 page = find_next_page_clear(first_page);
216 PFLAG_CLEAR_RANGE(first_page, page);
217
218 // Make the dirty pages read-only again
219 const int32 offset = first_page << mainBuffer.pageBits;
220 const uint32 length = (page - first_page) << mainBuffer.pageBits;
221 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
222
223 // There is at least one line to update
224 const int y1 = mainBuffer.pageInfo[first_page].top;
225 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
226 const int height = y2 - y1 + 1;
227
228 const int bytes_per_row = VideoMonitor.bytes_per_row;
229 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
230 int i, j;
231
232 // Check for first column from left and first column
233 // from right that have changed
234 int x1, x2, width;
235 if (depth == 1) {
236
237 x1 = VideoMonitor.x - 1;
238 for (j = y1; j <= y2; j++) {
239 uint8 * const p1 = &the_buffer[j * bytes_per_row];
240 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
241 for (i = 0; i < (x1>>3); i++) {
242 if (p1[i] != p2[i]) {
243 x1 = i << 3;
244 break;
245 }
246 }
247 }
248
249 x2 = x1;
250 for (j = y2; j >= y1; j--) {
251 uint8 * const p1 = &the_buffer[j * bytes_per_row];
252 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
253 for (i = (VideoMonitor.x>>3) - 1; i > (x2>>3); i--) {
254 if (p1[i] != p2[i]) {
255 x2 = (i << 3) + 7;
256 break;
257 }
258 }
259 }
260 width = x2 - x1 + 1;
261
262 // Update the_host_buffer and copy of the_buffer
263 i = y1 * bytes_per_row + (x1 >> 3);
264 for (j = y1; j <= y2; j++) {
265 Screen_blit(the_host_buffer + i, the_buffer + i, width >> 3);
266 memcpy(the_buffer_copy + i, the_buffer + i, width >> 3);
267 i += bytes_per_row;
268 }
269
270 } else {
271
272 x1 = VideoMonitor.x * bytes_per_pixel - 1;
273 for (j = y1; j <= y2; j++) {
274 uint8 * const p1 = &the_buffer[j * bytes_per_row];
275 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
276 for (i = 0; i < x1; i++) {
277 if (p1[i] != p2[i]) {
278 x1 = i;
279 break;
280 }
281 }
282 }
283 x1 /= bytes_per_pixel;
284
285 x2 = x1 * bytes_per_pixel;
286 for (j = y2; j >= y1; j--) {
287 uint8 * const p1 = &the_buffer[j * bytes_per_row];
288 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
289 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
290 if (p1[i] != p2[i]) {
291 x2 = i;
292 break;
293 }
294 }
295 }
296 x2 /= bytes_per_pixel;
297 width = x2 - x1 + 1;
298
299 // Update the_host_buffer and copy of the_buffer
300 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
301 for (j = y1; j <= y2; j++) {
302 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
303 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
304 i += bytes_per_row;
305 }
306 }
307
308 if (have_shm)
309 XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
310 else
311 XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
312 }
313 mainBuffer.dirty = false;
314 }
315
316
317 /*
318 * Update display for DGA mode and VOSF
319 * (only in Direct Addressing mode)
320 */
321
322 #if REAL_ADDRESSING || DIRECT_ADDRESSING
323 static inline void update_display_dga_vosf(void)
324 {
325 int page = 0;
326 for (;;) {
327 const int first_page = find_next_page_set(page);
328 if (first_page >= mainBuffer.pageCount)
329 break;
330
331 page = find_next_page_clear(first_page);
332 PFLAG_CLEAR_RANGE(first_page, page);
333
334 // Make the dirty pages read-only again
335 const int32 offset = first_page << mainBuffer.pageBits;
336 const uint32 length = (page - first_page) << mainBuffer.pageBits;
337 mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
338
339 // I am sure that y2 >= y1 and depth != 1
340 const int y1 = mainBuffer.pageInfo[first_page].top;
341 const int y2 = mainBuffer.pageInfo[page - 1].bottom;
342
343 const int bytes_per_row = VideoMonitor.bytes_per_row;
344 const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
345 int i, j;
346
347 // Check for first column from left and first column
348 // from right that have changed
349 int x1 = VideoMonitor.x * bytes_per_pixel - 1;
350 for (j = y1; j <= y2; j++) {
351 uint8 * const p1 = &the_buffer[j * bytes_per_row];
352 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
353 for (i = 0; i < x1; i++) {
354 if (p1[i] != p2[i]) {
355 x1 = i;
356 break;
357 }
358 }
359 }
360 x1 /= bytes_per_pixel;
361
362 int x2 = x1 * bytes_per_pixel;
363 for (j = y2; j >= y1; j--) {
364 uint8 * const p1 = &the_buffer[j * bytes_per_row];
365 uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
366 for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
367 if (p1[i] != p2[i]) {
368 x2 = i;
369 break;
370 }
371 }
372 }
373 x2 /= bytes_per_pixel;
374
375 // Update the_host_buffer and copy of the_buffer
376 // There should be at least one pixel to copy
377 const int width = x2 - x1 + 1;
378 i = y1 * bytes_per_row + x1 * bytes_per_pixel;
379 for (j = y1; j <= y2; j++) {
380 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
381 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
382 i += bytes_per_row;
383 }
384 }
385 mainBuffer.dirty = false;
386 }
387 #endif
388
389 #endif /* ENABLE_VOSF */
390
391 #endif /* VIDEO_VOSF_H */