ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.13
Committed: 2001-01-28T14:05:19Z (23 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.12: +13 -198 lines
Log Message:
Mainly changes to the VOSF code:
- improved blitters selection
- improved blitters performance if UNALIGNED_PROFITABLE is set
- cleaned up 8 bpp blitters

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 gbeauche 1.1 # else
121     # error "No suitable subterfuge for Video on SEGV signals"
122     # endif
123     #else
124     # error "Can't do Video on SEGV signals"
125     #endif
126    
127    
128     /*
129     * Screen fault handler initialization
130     */
131    
132     #if defined(HAVE_SIGINFO_T)
133     static bool Screen_fault_handler_init()
134     {
135     // Setup SIGSEGV handler to process writes to frame buffer
136     sigemptyset(&vosf_sa.sa_mask);
137     vosf_sa.sa_sigaction = Screen_fault_handler;
138 cebix 1.5 vosf_sa.sa_flags = SA_SIGINFO;
139 gbeauche 1.1 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
140     }
141     #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
142     static bool Screen_fault_handler_init()
143     {
144     // Setup SIGSEGV handler to process writes to frame buffer
145     sigemptyset(&vosf_sa.sa_mask);
146     vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
147 cebix 1.7 #if !EMULATED_68K && defined(__NetBSD__)
148     sigaddset(&vosf_sa.sa_mask, SIGALRM);
149     vosf_sa.sa_flags = SA_ONSTACK;
150     #else
151 gbeauche 1.1 vosf_sa.sa_flags = 0;
152 cebix 1.7 #endif
153 gbeauche 1.1 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
154     }
155     #endif
156    
157    
158     /*
159     * Update display for Windowed mode and VOSF
160     */
161    
162 gbeauche 1.13 // From video_blit.cpp
163     extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length);
164     extern bool Screen_blitter_init(XVisualInfo * visual_info, bool native_byte_order);
165    
166 gbeauche 1.12 /* How can we deal with array overrun conditions ?
167    
168     The state of the framebuffer pages that have been touched are maintained
169     in the dirtyPages[] table. That table is (pageCount + 2) bytes long.
170    
171     Terminology
172    
173     "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1].
174     "CLEAR Page Guard" refers to the page following the Last Page but is always
175     in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR
176     Page Guard but is always in the SET state.
177    
178     Rough process
179    
180 gbeauche 1.13 The update routines must determine which pages have to be blitted to the
181 gbeauche 1.12 screen. This job consists in finding the first_page that was touched.
182     i.e. find the next page that is SET. Then, finding how many pages were
183     touched starting from first_page. i.e. find the next page that is CLEAR.
184    
185 gbeauche 1.13 There are two cases to check:
186 gbeauche 1.12
187     - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard
188     but it is beyond the valid pageCount value. Therefore, we exit from the
189     update routine.
190    
191     - Last Page is SET: first_page equals (pageCount - 1) and
192     find_next_page_clear() will reach the CLEAR Page Guard. We blit the last
193     page to the screen. On the next iteration, page equals pageCount and
194     find_next_page_set() will reach the SET Page Guard. We still safely exit
195     from the update routine because the SET Page Guard position is greater
196     than pageCount.
197     */
198    
199 gbeauche 1.1 static inline void update_display_window_vosf(void)
200     {
201     int page = 0;
202     for (;;) {
203 gbeauche 1.11 const int first_page = find_next_page_set(page);
204     if (first_page >= mainBuffer.pageCount)
205 gbeauche 1.1 break;
206 gbeauche 1.11
207     page = find_next_page_clear(first_page);
208     PFLAG_CLEAR_RANGE(first_page, page);
209 cebix 1.7
210 gbeauche 1.1 // Make the dirty pages read-only again
211     const int32 offset = first_page << mainBuffer.pageBits;
212     const uint32 length = (page - first_page) << mainBuffer.pageBits;
213     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
214    
215     // There is at least one line to update
216     const int y1 = mainBuffer.pageInfo[first_page].top;
217     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
218     const int height = y2 - y1 + 1;
219    
220     const int bytes_per_row = VideoMonitor.bytes_per_row;
221     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
222     int i, j;
223    
224     // Check for first column from left and first column
225     // from right that have changed
226 cebix 1.6 int x1, x2, width;
227     if (depth == 1) {
228    
229     x1 = VideoMonitor.x - 1;
230     for (j = y1; j <= y2; j++) {
231     uint8 * const p1 = &the_buffer[j * bytes_per_row];
232     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
233     for (i = 0; i < (x1>>3); i++) {
234     if (p1[i] != p2[i]) {
235     x1 = i << 3;
236     break;
237     }
238 gbeauche 1.1 }
239     }
240 cebix 1.6
241     x2 = x1;
242     for (j = y2; j >= y1; j--) {
243     uint8 * const p1 = &the_buffer[j * bytes_per_row];
244     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
245     for (i = (VideoMonitor.x>>3) - 1; i > (x2>>3); i--) {
246     if (p1[i] != p2[i]) {
247 cebix 1.7 x2 = (i << 3) + 7;
248 cebix 1.6 break;
249     }
250     }
251     }
252     width = x2 - x1 + 1;
253    
254     // Update the_host_buffer and copy of the_buffer
255     i = y1 * bytes_per_row + (x1 >> 3);
256     for (j = y1; j <= y2; j++) {
257 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, width >> 3);
258 cebix 1.6 memcpy(the_buffer_copy + i, the_buffer + i, width >> 3);
259     i += bytes_per_row;
260     }
261    
262     } else {
263    
264     x1 = VideoMonitor.x * bytes_per_pixel - 1;
265     for (j = y1; j <= y2; j++) {
266     uint8 * const p1 = &the_buffer[j * bytes_per_row];
267     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
268     for (i = 0; i < x1; i++) {
269     if (p1[i] != p2[i]) {
270     x1 = i;
271     break;
272     }
273     }
274     }
275     x1 /= bytes_per_pixel;
276 gbeauche 1.1
277 cebix 1.6 x2 = x1 * bytes_per_pixel;
278     for (j = y2; j >= y1; j--) {
279     uint8 * const p1 = &the_buffer[j * bytes_per_row];
280     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
281     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
282     if (p1[i] != p2[i]) {
283     x2 = i;
284     break;
285     }
286 gbeauche 1.1 }
287     }
288 cebix 1.6 x2 /= bytes_per_pixel;
289     width = x2 - x1 + 1;
290    
291     // Update the_host_buffer and copy of the_buffer
292     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
293     for (j = y1; j <= y2; j++) {
294 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
295 cebix 1.6 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
296     i += bytes_per_row;
297     }
298 gbeauche 1.1 }
299    
300     if (have_shm)
301     XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
302     else
303     XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
304     }
305 gbeauche 1.13 mainBuffer.dirty = false;
306 gbeauche 1.1 }
307    
308    
309     /*
310     * Update display for DGA mode and VOSF
311     * (only in Direct Addressing mode)
312     */
313    
314     #if REAL_ADDRESSING || DIRECT_ADDRESSING
315     static inline void update_display_dga_vosf(void)
316     {
317     int page = 0;
318     for (;;) {
319 gbeauche 1.11 const int first_page = find_next_page_set(page);
320     if (first_page >= mainBuffer.pageCount)
321 gbeauche 1.1 break;
322 gbeauche 1.11
323     page = find_next_page_clear(first_page);
324     PFLAG_CLEAR_RANGE(first_page, page);
325    
326 gbeauche 1.1 // Make the dirty pages read-only again
327     const int32 offset = first_page << mainBuffer.pageBits;
328     const uint32 length = (page - first_page) << mainBuffer.pageBits;
329     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
330    
331     // I am sure that y2 >= y1 and depth != 1
332     const int y1 = mainBuffer.pageInfo[first_page].top;
333     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
334    
335     const int bytes_per_row = VideoMonitor.bytes_per_row;
336     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
337     int i, j;
338    
339     // Check for first column from left and first column
340     // from right that have changed
341     int x1 = VideoMonitor.x * bytes_per_pixel - 1;
342     for (j = y1; j <= y2; j++) {
343     uint8 * const p1 = &the_buffer[j * bytes_per_row];
344     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
345     for (i = 0; i < x1; i++) {
346     if (p1[i] != p2[i]) {
347     x1 = i;
348     break;
349     }
350     }
351     }
352     x1 /= bytes_per_pixel;
353    
354     int x2 = x1 * bytes_per_pixel;
355     for (j = y2; j >= y1; j--) {
356     uint8 * const p1 = &the_buffer[j * bytes_per_row];
357     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
358     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
359     if (p1[i] != p2[i]) {
360     x2 = i;
361     break;
362     }
363     }
364     }
365     x2 /= bytes_per_pixel;
366    
367     // Update the_host_buffer and copy of the_buffer
368     // There should be at least one pixel to copy
369     const int width = x2 - x1 + 1;
370     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
371     for (j = y1; j <= y2; j++) {
372 gbeauche 1.13 Screen_blit(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
373 gbeauche 1.1 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
374     i += bytes_per_row;
375     }
376     }
377 gbeauche 1.13 mainBuffer.dirty = false;
378 gbeauche 1.1 }
379     #endif
380    
381     #endif /* ENABLE_VOSF */
382    
383     #endif /* VIDEO_VOSF_H */