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

# 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     // Align on page boundaries
32 gbeauche 1.4 static uintptr align_on_page_boundary(uintptr 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     // 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 gbeauche 1.11 const uintptr INVALID_PC = (uintptr)-1;
52    
53     static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
54 gbeauche 1.1 {
55 gbeauche 1.11 /* 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 gbeauche 1.13 mainBuffer.dirty = true;
66 gbeauche 1.11 UNLOCK_VOSF;
67     return;
68 gbeauche 1.1 }
69    
70 gbeauche 1.11 /* 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 gbeauche 1.1 }
78    
79     #if defined(HAVE_SIGINFO_T)
80 cebix 1.6
81 gbeauche 1.1 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 gbeauche 1.4 do_handle_screen_fault((uintptr)sip->si_addr);
85 gbeauche 1.1 }
86 cebix 1.6
87 gbeauche 1.1 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
88 cebix 1.6
89 gbeauche 1.1 # 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 gbeauche 1.11 do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
94 gbeauche 1.1 }
95 cebix 1.6
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 cebix 1.14 # 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 gbeauche 1.1 # 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 cebix 1.5 vosf_sa.sa_flags = SA_SIGINFO;
147 gbeauche 1.1 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 cebix 1.7 #if !EMULATED_68K && defined(__NetBSD__)
156     sigaddset(&vosf_sa.sa_mask, SIGALRM);
157     vosf_sa.sa_flags = SA_ONSTACK;
158     #else
159 gbeauche 1.1 vosf_sa.sa_flags = 0;
160 cebix 1.7 #endif
161 gbeauche 1.1 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
162     }
163     #endif
164    
165    
166     /*
167     * Update display for Windowed mode and VOSF
168     */
169    
170 gbeauche 1.13 // 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 gbeauche 1.12 /* 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 gbeauche 1.13 The update routines must determine which pages have to be blitted to the
189 gbeauche 1.12 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 gbeauche 1.13 There are two cases to check:
194 gbeauche 1.12
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 gbeauche 1.1 static inline void update_display_window_vosf(void)
208     {
209     int page = 0;
210     for (;;) {
211 gbeauche 1.11 const int first_page = find_next_page_set(page);
212     if (first_page >= mainBuffer.pageCount)
213 gbeauche 1.1 break;
214 gbeauche 1.11
215     page = find_next_page_clear(first_page);
216     PFLAG_CLEAR_RANGE(first_page, page);
217 cebix 1.7
218 gbeauche 1.1 // 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 cebix 1.6 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 gbeauche 1.1 }
247     }
248 cebix 1.6
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 cebix 1.7 x2 = (i << 3) + 7;
256 cebix 1.6 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 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, width >> 3);
266 cebix 1.6 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 gbeauche 1.1
285 cebix 1.6 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 gbeauche 1.1 }
295     }
296 cebix 1.6 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 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
303 cebix 1.6 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
304     i += bytes_per_row;
305     }
306 gbeauche 1.1 }
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 gbeauche 1.13 mainBuffer.dirty = false;
314 gbeauche 1.1 }
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 gbeauche 1.11 const int first_page = find_next_page_set(page);
328     if (first_page >= mainBuffer.pageCount)
329 gbeauche 1.1 break;
330 gbeauche 1.11
331     page = find_next_page_clear(first_page);
332     PFLAG_CLEAR_RANGE(first_page, page);
333    
334 gbeauche 1.1 // 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 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
381 gbeauche 1.1 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
382     i += bytes_per_row;
383     }
384     }
385 gbeauche 1.13 mainBuffer.dirty = false;
386 gbeauche 1.1 }
387     #endif
388    
389     #endif /* ENABLE_VOSF */
390    
391     #endif /* VIDEO_VOSF_H */