ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.11
Committed: 2001-01-11T16:39:08Z (23 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.10: +34 -38 lines
Log Message:
Changes made to the update routines
- Cleaned up the process for determining the ranges of pages touched
  that have to be blitted onto the screen (find_next_page_set() and
  find_next_page_clear() functions)
Changes made to do_handle_screen_fault()
- An unhandled address is now dealt by the default SIGSEGV handler
- Print out the address of the instruction that caused the exception

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * video_vosf.h - Video/graphics emulation, video on SEGV signals support
3     *
4     * Basilisk II (C) 1997-2000 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 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 depth identification
49     */
50    
51     enum {
52     ID_DEPTH_UNKNOWN = -1,
53     ID_DEPTH_1,
54     ID_DEPTH_8,
55     ID_DEPTH_15,
56     ID_DEPTH_16,
57     ID_DEPTH_24,
58     ID_DEPTH_32 = ID_DEPTH_24,
59     ID_DEPTH_COUNT
60     };
61    
62     static int depth_id(int depth)
63     {
64     int id;
65     switch (depth) {
66     case 1 : id = ID_DEPTH_1; break;
67     case 8 : id = ID_DEPTH_8; break;
68     case 15 : id = ID_DEPTH_15; break;
69     case 16 : id = ID_DEPTH_16; break;
70     case 24 : id = ID_DEPTH_24; break;
71     case 32 : id = ID_DEPTH_32; break;
72     default : id = ID_DEPTH_UNKNOWN;
73     }
74     return id;
75     }
76    
77    
78     /*
79     * Frame buffer copy function templates
80     */
81    
82     // No conversion required
83    
84     #define MEMCPY_PROFITABLE
85     #ifdef MEMCPY_PROFITABLE
86     static void do_fbcopy_raw(uint8 * dest, const uint8 * source, uint32 length)
87     {
88     memcpy(dest, source, length);
89     }
90     #else
91     #define FB_BLIT_1(dst, src) (dst = (src))
92     #define FB_BLIT_2(dst, src) (dst = (src))
93 gbeauche 1.2 #define FB_DEPTH 0
94 gbeauche 1.1 #define FB_FUNC_NAME do_fbcopy_raw
95     #include "video_blit.h"
96     #endif
97    
98    
99     // RGB 555
100    
101 gbeauche 1.2 #ifdef WORDS_BIGENDIAN
102     # define FB_FUNC_NAME do_fbcopy_15_obo
103     #else
104     # define FB_FUNC_NAME do_fbcopy_15_nbo
105     #endif
106    
107 gbeauche 1.1 #define FB_BLIT_1(dst, src) \
108     (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8))
109    
110     #define FB_BLIT_2(dst, src) \
111     (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8))
112    
113     #define FB_DEPTH 15
114     #include "video_blit.h"
115    
116    
117     // RGB 565
118    
119 gbeauche 1.2 #ifdef WORDS_BIGENDIAN
120    
121     // native byte order
122    
123     #define FB_BLIT_1(dst, src) \
124     (dst = (((src) & 0x1f) | (((src) << 1) & 0xffc0)))
125    
126     #define FB_BLIT_2(dst, src) \
127     (dst = (((src) & 0x001f001f) | (((src) << 1) & 0xffc0ffc0)))
128    
129     #define FB_DEPTH 16
130     #define FB_FUNC_NAME do_fbcopy_16_nbo
131     #include "video_blit.h"
132    
133 cebix 1.9 // opposite byte order
134 gbeauche 1.2
135     #define FB_BLIT_1(dst, src) \
136 cebix 1.9 (dst = ((((src) >> 7) & 0xff) | (((src) << 9) & 0xc000) | (((src) << 8) & 0x1f00)))
137 gbeauche 1.2
138     #define FB_BLIT_2(dst, src) \
139 cebix 1.9 (dst = ((((src) >> 7) & 0x00ff00ff) | (((src) << 9) & 0xc000c000) | (((src) << 8) & 0x1f001f00)))
140 gbeauche 1.2
141     #define FB_DEPTH 16
142     #define FB_FUNC_NAME do_fbcopy_16_obo
143     #include "video_blit.h"
144    
145     #else
146    
147     // native byte order
148    
149 gbeauche 1.1 #define FB_BLIT_1(dst, src) \
150     (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0))
151    
152     #define FB_BLIT_2(dst, src) \
153     (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0))
154    
155     #define FB_DEPTH 16
156 gbeauche 1.2 #define FB_FUNC_NAME do_fbcopy_16_nbo
157 gbeauche 1.1 #include "video_blit.h"
158    
159 gbeauche 1.2 // opposite byte order (untested)
160    
161     #define FB_BLIT_1(dst, src) \
162     (dst = (((src) & 0x1f00) | (((src) << 1) & 0xe0fe) | (((src) >> 15) & 1)))
163    
164     #define FB_BLIT_2(dst, src) \
165     (dst = (((src) & 0x1f001f00) | (((src) << 1) & 0xe0fee0fe) | (((src) >> 15) & 0x10001)))
166    
167     #define FB_DEPTH 16
168     #define FB_FUNC_NAME do_fbcopy_16_obo
169     #include "video_blit.h"
170    
171     #endif
172 gbeauche 1.1
173     // RGB 888
174    
175 gbeauche 1.2 #ifdef WORDS_BIGENDIAN
176     # define FB_FUNC_NAME do_fbcopy_24_obo
177     #else
178     # define FB_FUNC_NAME do_fbcopy_24_nbo
179     #endif
180    
181 gbeauche 1.1 #define FB_BLIT_1(dst, src) \
182     (dst = (src))
183    
184     #define FB_BLIT_2(dst, src) \
185 gbeauche 1.4 (dst = (((src) >> 24) & 0xff) | (((src) >> 8) & 0xff00) | (((src) & 0xff00) << 8) | (((src) & 0xff) << 24))
186 gbeauche 1.1
187     #define FB_DEPTH 24
188     #include "video_blit.h"
189    
190    
191     /*
192     * Frame buffer copy functions map table
193     */
194    
195     typedef void (*fbcopy_func)(uint8 *, const uint8 *, uint32);
196     static fbcopy_func do_update_framebuffer;
197    
198     #define FBCOPY_FUNC(aHandler) do_ ## aHandler
199    
200     #if REAL_ADDRESSING || DIRECT_ADDRESSING
201     #define WD(X) { FBCOPY_FUNC(X), FBCOPY_FUNC(X) }
202     #else
203     #define WD(X) { FBCOPY_FUNC(fbcopy_raw), FBCOPY_FUNC(fbcopy_raw) }
204     #endif
205    
206     // fb_copy_funcs[depth_id][native_byte_order][dga_mode]
207     // NT : not tested
208     // OK : has been successfully tested
209 cebix 1.10 // NBO : native byte order (X server vs. client)
210     // OBO : opposite byte order (X server vs. client)
211 gbeauche 1.1 static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
212     #ifdef WORDS_BIGENDIAN
213 gbeauche 1.2 /* opposite byte order native byte order */
214     /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
215     /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
216 cebix 1.10 /* 15 bpp */ { WD(fbcopy_15_obo) , WD(fbcopy_raw) }, // OK (OBO)
217 cebix 1.9 /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (OBO)
218 cebix 1.10 /* 24 bpp */ { WD(fbcopy_24_obo) , WD(fbcopy_raw) } // OK (OBO)
219 gbeauche 1.1 #else
220 gbeauche 1.2 /* opposite byte order native byte order */
221     /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
222     /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
223     /* 15 bpp */ { WD(fbcopy_raw) , WD(fbcopy_15_nbo) }, // OK (NBO)
224     /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (NBO)
225 cebix 1.10 /* 24 bpp */ { WD(fbcopy_raw) , WD(fbcopy_24_nbo) } // OK (NBO)
226 gbeauche 1.1 #endif
227     };
228    
229     #undef WD
230    
231     #define FBCOPY_FUNC_ERROR \
232     ErrorAlert("Invalid screen depth")
233    
234     #define GET_FBCOPY_FUNC(aDepth, aNativeByteOrder, aDisplay) \
235     ((depth_id(aDepth) == ID_DEPTH_UNKNOWN) ? ( FBCOPY_FUNC_ERROR, (fbcopy_func)0 ) : \
236     fbcopy_funcs[depth_id(aDepth)][(aNativeByteOrder)][(aDisplay) == DISPLAY_DGA ? 1 : 0])
237    
238    
239     /*
240     * Screen fault handler
241     */
242    
243 gbeauche 1.11 const uintptr INVALID_PC = (uintptr)-1;
244    
245     static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
246 gbeauche 1.1 {
247 gbeauche 1.11 /* Someone attempted to write to the frame buffer. Make it writeable
248     * now so that the data could actually be written. It will be made
249     * read-only back in one of the screen update_*() functions.
250     */
251     if ((addr >= mainBuffer.memStart) && (addr < mainBuffer.memEnd)) {
252     const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
253     caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
254     LOCK_VOSF;
255     PFLAG_SET(page);
256     mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
257     UNLOCK_VOSF;
258     return;
259 gbeauche 1.1 }
260    
261 gbeauche 1.11 /* Otherwise, we don't know how to handle the fault, let it crash */
262     fprintf(stderr, "do_handle_screen_fault: unhandled address 0x%08X", addr);
263     if (pc != INVALID_PC)
264     fprintf(stderr, " [IP=0x%08X]", pc);
265     fprintf(stderr, "\n");
266    
267     signal(SIGSEGV, SIG_DFL);
268 gbeauche 1.1 }
269    
270     #if defined(HAVE_SIGINFO_T)
271 cebix 1.6
272 gbeauche 1.1 static void Screen_fault_handler(int, siginfo_t * sip, void *)
273     {
274     D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
275 gbeauche 1.4 do_handle_screen_fault((uintptr)sip->si_addr);
276 gbeauche 1.1 }
277 cebix 1.6
278 gbeauche 1.1 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
279 cebix 1.6
280 gbeauche 1.1 # if defined(__i386__) && defined(__linux__)
281     static void Screen_fault_handler(int, struct sigcontext scs)
282     {
283     D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
284 gbeauche 1.11 do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
285 gbeauche 1.1 }
286 cebix 1.6
287     # elif defined(__m68k__) && defined(__NetBSD__)
288    
289     # include <m68k/frame.h>
290     static void Screen_fault_handler(int, int code, struct sigcontext *scp)
291     {
292     D(bug("Screen_fault_handler: ADDR=0x%08X\n", code));
293     struct sigstate {
294     int ss_flags;
295     struct frame ss_frame;
296     };
297     struct sigstate *state = (struct sigstate *)scp->sc_ap;
298     uintptr fault_addr;
299     switch (state->ss_frame.f_format) {
300     case 7: // 68040 access error
301     // "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown
302     fault_addr = state->ss_frame.f_fmt7.f_fa;
303     break;
304     default:
305     fault_addr = (uintptr)code;
306     break;
307     }
308     do_handle_screen_fault(fault_addr);
309     }
310    
311 gbeauche 1.1 # else
312     # error "No suitable subterfuge for Video on SEGV signals"
313     # endif
314     #else
315     # error "Can't do Video on SEGV signals"
316     #endif
317    
318    
319     /*
320     * Screen fault handler initialization
321     */
322    
323     #if defined(HAVE_SIGINFO_T)
324     static bool Screen_fault_handler_init()
325     {
326     // Setup SIGSEGV handler to process writes to frame buffer
327     sigemptyset(&vosf_sa.sa_mask);
328     vosf_sa.sa_sigaction = Screen_fault_handler;
329 cebix 1.5 vosf_sa.sa_flags = SA_SIGINFO;
330 gbeauche 1.1 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
331     }
332     #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
333     static bool Screen_fault_handler_init()
334     {
335     // Setup SIGSEGV handler to process writes to frame buffer
336     sigemptyset(&vosf_sa.sa_mask);
337     vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
338 cebix 1.7 #if !EMULATED_68K && defined(__NetBSD__)
339     sigaddset(&vosf_sa.sa_mask, SIGALRM);
340     vosf_sa.sa_flags = SA_ONSTACK;
341     #else
342 gbeauche 1.1 vosf_sa.sa_flags = 0;
343 cebix 1.7 #endif
344 gbeauche 1.1 return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
345     }
346     #endif
347    
348    
349     /*
350     * Update display for Windowed mode and VOSF
351     */
352    
353     static inline void update_display_window_vosf(void)
354     {
355     int page = 0;
356     for (;;) {
357 gbeauche 1.11 const int first_page = find_next_page_set(page);
358     if (first_page >= mainBuffer.pageCount)
359 gbeauche 1.1 break;
360 gbeauche 1.11
361     page = find_next_page_clear(first_page);
362     PFLAG_CLEAR_RANGE(first_page, page);
363 cebix 1.7
364 gbeauche 1.1 // Make the dirty pages read-only again
365     const int32 offset = first_page << mainBuffer.pageBits;
366     const uint32 length = (page - first_page) << mainBuffer.pageBits;
367     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
368    
369     // There is at least one line to update
370     const int y1 = mainBuffer.pageInfo[first_page].top;
371     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
372     const int height = y2 - y1 + 1;
373    
374     const int bytes_per_row = VideoMonitor.bytes_per_row;
375     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
376     int i, j;
377    
378     // Check for first column from left and first column
379     // from right that have changed
380 cebix 1.6 int x1, x2, width;
381     if (depth == 1) {
382    
383     x1 = VideoMonitor.x - 1;
384     for (j = y1; j <= y2; j++) {
385     uint8 * const p1 = &the_buffer[j * bytes_per_row];
386     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
387     for (i = 0; i < (x1>>3); i++) {
388     if (p1[i] != p2[i]) {
389     x1 = i << 3;
390     break;
391     }
392 gbeauche 1.1 }
393     }
394 cebix 1.6
395     x2 = x1;
396     for (j = y2; j >= y1; j--) {
397     uint8 * const p1 = &the_buffer[j * bytes_per_row];
398     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
399     for (i = (VideoMonitor.x>>3) - 1; i > (x2>>3); i--) {
400     if (p1[i] != p2[i]) {
401 cebix 1.7 x2 = (i << 3) + 7;
402 cebix 1.6 break;
403     }
404     }
405     }
406     width = x2 - x1 + 1;
407    
408     // Update the_host_buffer and copy of the_buffer
409     i = y1 * bytes_per_row + (x1 >> 3);
410     for (j = y1; j <= y2; j++) {
411     do_update_framebuffer(the_host_buffer + i, the_buffer + i, width >> 3);
412     memcpy(the_buffer_copy + i, the_buffer + i, width >> 3);
413     i += bytes_per_row;
414     }
415    
416     } else {
417    
418     x1 = VideoMonitor.x * bytes_per_pixel - 1;
419     for (j = y1; j <= y2; j++) {
420     uint8 * const p1 = &the_buffer[j * bytes_per_row];
421     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
422     for (i = 0; i < x1; i++) {
423     if (p1[i] != p2[i]) {
424     x1 = i;
425     break;
426     }
427     }
428     }
429     x1 /= bytes_per_pixel;
430 gbeauche 1.1
431 cebix 1.6 x2 = x1 * bytes_per_pixel;
432     for (j = y2; j >= y1; j--) {
433     uint8 * const p1 = &the_buffer[j * bytes_per_row];
434     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
435     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
436     if (p1[i] != p2[i]) {
437     x2 = i;
438     break;
439     }
440 gbeauche 1.1 }
441     }
442 cebix 1.6 x2 /= bytes_per_pixel;
443     width = x2 - x1 + 1;
444    
445     // Update the_host_buffer and copy of the_buffer
446     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
447     for (j = y1; j <= y2; j++) {
448     do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
449     memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
450     i += bytes_per_row;
451     }
452 gbeauche 1.1 }
453    
454     if (have_shm)
455     XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
456     else
457     XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
458     }
459     }
460    
461    
462     /*
463     * Update display for DGA mode and VOSF
464     * (only in Direct Addressing mode)
465     */
466    
467     #if REAL_ADDRESSING || DIRECT_ADDRESSING
468     static inline void update_display_dga_vosf(void)
469     {
470     int page = 0;
471     for (;;) {
472 gbeauche 1.11 const int first_page = find_next_page_set(page);
473     if (first_page >= mainBuffer.pageCount)
474 gbeauche 1.1 break;
475 gbeauche 1.11
476     page = find_next_page_clear(first_page);
477     PFLAG_CLEAR_RANGE(first_page, page);
478    
479 gbeauche 1.1 // Make the dirty pages read-only again
480     const int32 offset = first_page << mainBuffer.pageBits;
481     const uint32 length = (page - first_page) << mainBuffer.pageBits;
482     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
483    
484     // I am sure that y2 >= y1 and depth != 1
485     const int y1 = mainBuffer.pageInfo[first_page].top;
486     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
487    
488     const int bytes_per_row = VideoMonitor.bytes_per_row;
489     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
490     int i, j;
491    
492     // Check for first column from left and first column
493     // from right that have changed
494     int x1 = VideoMonitor.x * bytes_per_pixel - 1;
495     for (j = y1; j <= y2; j++) {
496     uint8 * const p1 = &the_buffer[j * bytes_per_row];
497     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
498     for (i = 0; i < x1; i++) {
499     if (p1[i] != p2[i]) {
500     x1 = i;
501     break;
502     }
503     }
504     }
505     x1 /= bytes_per_pixel;
506    
507     int x2 = x1 * bytes_per_pixel;
508     for (j = y2; j >= y1; j--) {
509     uint8 * const p1 = &the_buffer[j * bytes_per_row];
510     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
511     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
512     if (p1[i] != p2[i]) {
513     x2 = i;
514     break;
515     }
516     }
517     }
518     x2 /= bytes_per_pixel;
519    
520     // Update the_host_buffer and copy of the_buffer
521     // There should be at least one pixel to copy
522     const int width = x2 - x1 + 1;
523     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
524     for (j = y1; j <= y2; j++) {
525     do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
526     memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
527     i += bytes_per_row;
528     }
529     }
530     }
531     #endif
532    
533     #endif /* ENABLE_VOSF */
534    
535     #endif /* VIDEO_VOSF_H */