ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/video_vosf.h
Revision: 1.1
Committed: 2000-09-22T17:16:05Z (23 years, 11 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Log Message:
- video on SEGV signals

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     static uint32 align_on_page_boundary(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     // 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     #error "incomplete"
92     #define FB_BLIT_1(dst, src) (dst = (src))
93     #define FB_BLIT_2(dst, src) (dst = (src))
94     #define FB_DEPTH 8
95     #define FB_FUNC_NAME do_fbcopy_raw
96     #include "video_blit.h"
97     #endif
98    
99    
100     // RGB 555
101    
102     #define FB_BLIT_1(dst, src) \
103     (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8))
104    
105     #define FB_BLIT_2(dst, src) \
106     (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8))
107    
108     #define FB_DEPTH 15
109     #define FB_FUNC_NAME do_fbcopy_15
110     #include "video_blit.h"
111    
112    
113     // RGB 565
114    
115     #define FB_BLIT_1(dst, src) \
116     (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0))
117    
118     #define FB_BLIT_2(dst, src) \
119     (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0))
120    
121     #define FB_DEPTH 16
122     #define FB_FUNC_NAME do_fbcopy_16
123     #include "video_blit.h"
124    
125    
126     // RGB 888
127    
128     #define FB_BLIT_1(dst, src) \
129     (dst = (src))
130    
131     #define FB_BLIT_2(dst, src) \
132     (dst = (((src) >> 24) & 0xff) | (((src) >> 16) & 0xff00) | (((src) & 0xff00) << 16) | (((src) & 0xff) << 24))
133    
134     #define FB_DEPTH 24
135     #define FB_FUNC_NAME do_fbcopy_24
136     #include "video_blit.h"
137    
138    
139     /*
140     * Frame buffer copy functions map table
141     */
142    
143     typedef void (*fbcopy_func)(uint8 *, const uint8 *, uint32);
144     static fbcopy_func do_update_framebuffer;
145    
146     #define FBCOPY_FUNC(aHandler) do_ ## aHandler
147    
148     #if REAL_ADDRESSING || DIRECT_ADDRESSING
149     #define WD(X) { FBCOPY_FUNC(X), FBCOPY_FUNC(X) }
150     #else
151     #define WD(X) { FBCOPY_FUNC(fbcopy_raw), FBCOPY_FUNC(fbcopy_raw) }
152     #endif
153    
154     // fb_copy_funcs[depth_id][native_byte_order][dga_mode]
155     // NT : not tested
156     // OK : has been successfully tested
157     // NBO : native byte order
158     static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
159     #ifdef WORDS_BIGENDIAN
160     /* alt byte order native byte order */
161     /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
162     /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
163     /* 15 bpp */ { WD(fbcopy_15) , WD(fbcopy_raw) }, // NT
164     /* 16 bpp */ { WD(fbcopy_16) , WD(fbcopy_raw) }, // NT
165     /* 24 bpp */ { WD(fbcopy_24) , WD(fbcopy_raw) } // NT
166     #else
167     /* 1 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // NT
168     /* 8 bpp */ { WD(fbcopy_raw) , WD(fbcopy_raw) }, // OK (NBO)
169     /* 15 bpp */ { WD(fbcopy_15) , WD(fbcopy_15) }, // OK (NBO)
170     /* 16 bpp */ { WD(fbcopy_16) , WD(fbcopy_16) }, // OK (NBO)
171     /* 24 bpp */ { WD(fbcopy_24) , WD(fbcopy_24) } // NT
172     #endif
173     };
174    
175     #undef WD
176    
177     #define FBCOPY_FUNC_ERROR \
178     ErrorAlert("Invalid screen depth")
179    
180     #define GET_FBCOPY_FUNC(aDepth, aNativeByteOrder, aDisplay) \
181     ((depth_id(aDepth) == ID_DEPTH_UNKNOWN) ? ( FBCOPY_FUNC_ERROR, (fbcopy_func)0 ) : \
182     fbcopy_funcs[depth_id(aDepth)][(aNativeByteOrder)][(aDisplay) == DISPLAY_DGA ? 1 : 0])
183    
184    
185     /*
186     * Screen fault handler
187     */
188    
189     static inline void do_handle_screen_fault(unsigned long addr)
190     {
191     if ((addr < mainBuffer.memStart) || (addr >= mainBuffer.memEnd)) {
192     fprintf(stderr, "Segmentation fault at 0x%08X\n", addr);
193     abort();
194     }
195    
196     const int page = (addr - mainBuffer.memStart) >> mainBuffer.pageBits;
197     caddr_t page_ad = (caddr_t)(addr & ~(mainBuffer.pageSize - 1));
198     #ifdef HAVE_PTHREADS
199     pthread_mutex_lock(&Screen_draw_lock);
200     #endif
201     PFLAG_SET(page);
202     mprotect(page_ad, mainBuffer.pageSize, PROT_READ | PROT_WRITE);
203     #ifdef HAVE_PTHREADS
204     pthread_mutex_unlock(&Screen_draw_lock);
205     #endif
206     }
207    
208     #if defined(HAVE_SIGINFO_T)
209     static void Screen_fault_handler(int, siginfo_t * sip, void *)
210     {
211     D(bug("Screen_fault_handler: ADDR=0x%08X\n", sip->si_addr));
212     do_handle_screen_fault((unsigned long)sip->si_addr);
213     }
214     #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
215     # if defined(__i386__) && defined(__linux__)
216     static void Screen_fault_handler(int, struct sigcontext scs)
217     {
218     D(bug("Screen_fault_handler: ADDR=0x%08X from IP=0x%08X\n", scs.cr2, scs.eip));
219     do_handle_screen_fault((unsigned long)scs.cr2);
220     }
221     # else
222     # error "No suitable subterfuge for Video on SEGV signals"
223     # endif
224     #else
225     # error "Can't do Video on SEGV signals"
226     #endif
227    
228    
229     /*
230     * Screen fault handler initialization
231     */
232    
233     #if defined(HAVE_SIGINFO_T)
234     static bool Screen_fault_handler_init()
235     {
236     // Setup SIGSEGV handler to process writes to frame buffer
237     sigemptyset(&vosf_sa.sa_mask);
238     vosf_sa.sa_sigaction = Screen_fault_handler;
239     vosf_sa.sa_flags = 0;
240     return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
241     }
242     #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
243     static bool Screen_fault_handler_init()
244     {
245     // Setup SIGSEGV handler to process writes to frame buffer
246     sigemptyset(&vosf_sa.sa_mask);
247     vosf_sa.sa_handler = (void (*)(int)) Screen_fault_handler;
248     vosf_sa.sa_flags = 0;
249     return (sigaction(SIGSEGV, &vosf_sa, NULL) == 0);
250     }
251     #endif
252    
253    
254     /*
255     * Update display for Windowed mode and VOSF
256     */
257    
258     static inline void update_display_window_vosf(void)
259     {
260     int page = 0;
261     for (;;) {
262     while (PFLAG_ISCLEAR_4(page))
263     page += 4;
264    
265     while (PFLAG_ISCLEAR(page))
266     page++;
267    
268     if (page >= mainBuffer.pageCount)
269     break;
270    
271     const int first_page = page;
272     PFLAG_CLEAR(first_page);
273     while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
274     PFLAG_CLEAR(page);
275    
276     // Make the dirty pages read-only again
277     const int32 offset = first_page << mainBuffer.pageBits;
278     const uint32 length = (page - first_page) << mainBuffer.pageBits;
279     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
280    
281     // There is at least one line to update
282     const int y1 = mainBuffer.pageInfo[first_page].top;
283     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
284     const int height = y2 - y1 + 1;
285    
286     const int bytes_per_row = VideoMonitor.bytes_per_row;
287     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
288     int i, j;
289    
290     // Check for first column from left and first column
291     // from right that have changed
292     int x1 = VideoMonitor.x * bytes_per_pixel - 1;
293     for (j = y1; j <= y2; j++) {
294     uint8 * const p1 = &the_buffer[j * bytes_per_row];
295     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
296     for (i = 0; i < x1; i++) {
297     if (p1[i] != p2[i]) {
298     x1 = i;
299     break;
300     }
301     }
302     }
303     x1 /= bytes_per_pixel;
304    
305     int x2 = x1 * bytes_per_pixel;
306     for (j = y2; j >= y1; j--) {
307     uint8 * const p1 = &the_buffer[j * bytes_per_row];
308     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
309     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
310     if (p1[i] != p2[i]) {
311     x2 = i;
312     break;
313     }
314     }
315     }
316     x2 /= bytes_per_pixel;
317    
318     // Update the_host_buffer and copy of the_buffer
319     // There is at least one pixel to copy
320     const int width = x2 - x1 + 1;
321     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
322     for (j = y1; j <= y2; j++) {
323     do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
324     memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
325     i += bytes_per_row;
326     }
327    
328     if (have_shm)
329     XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height, 0);
330     else
331     XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, width, height);
332     }
333     }
334    
335    
336     /*
337     * Update display for DGA mode and VOSF
338     * (only in Direct Addressing mode)
339     */
340    
341     #if REAL_ADDRESSING || DIRECT_ADDRESSING
342     static inline void update_display_dga_vosf(void)
343     {
344     int page = 0;
345     for (;;) {
346     while (PFLAG_ISCLEAR_4(page))
347     page += 4;
348    
349     while (PFLAG_ISCLEAR(page))
350     page++;
351    
352     if (page >= mainBuffer.pageCount)
353     break;
354    
355     const int first_page = page;
356     PFLAG_CLEAR(first_page);
357     while ((++page < mainBuffer.pageCount) && PFLAG_ISSET(page))
358     PFLAG_CLEAR(page);
359    
360     // Make the dirty pages read-only again
361     const int32 offset = first_page << mainBuffer.pageBits;
362     const uint32 length = (page - first_page) << mainBuffer.pageBits;
363     mprotect((caddr_t)(mainBuffer.memStart + offset), length, PROT_READ);
364    
365     // I am sure that y2 >= y1 and depth != 1
366     const int y1 = mainBuffer.pageInfo[first_page].top;
367     const int y2 = mainBuffer.pageInfo[page - 1].bottom;
368    
369     const int bytes_per_row = VideoMonitor.bytes_per_row;
370     const int bytes_per_pixel = VideoMonitor.bytes_per_row / VideoMonitor.x;
371     int i, j;
372    
373     // Check for first column from left and first column
374     // from right that have changed
375     int x1 = VideoMonitor.x * bytes_per_pixel - 1;
376     for (j = y1; j <= y2; j++) {
377     uint8 * const p1 = &the_buffer[j * bytes_per_row];
378     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
379     for (i = 0; i < x1; i++) {
380     if (p1[i] != p2[i]) {
381     x1 = i;
382     break;
383     }
384     }
385     }
386     x1 /= bytes_per_pixel;
387    
388     int x2 = x1 * bytes_per_pixel;
389     for (j = y2; j >= y1; j--) {
390     uint8 * const p1 = &the_buffer[j * bytes_per_row];
391     uint8 * const p2 = &the_buffer_copy[j * bytes_per_row];
392     for (i = VideoMonitor.x * bytes_per_pixel - 1; i > x2; i--) {
393     if (p1[i] != p2[i]) {
394     x2 = i;
395     break;
396     }
397     }
398     }
399     x2 /= bytes_per_pixel;
400    
401     // Update the_host_buffer and copy of the_buffer
402     // There should be at least one pixel to copy
403     const int width = x2 - x1 + 1;
404     i = y1 * bytes_per_row + x1 * bytes_per_pixel;
405     for (j = y1; j <= y2; j++) {
406     do_update_framebuffer(the_host_buffer + i, the_buffer + i, bytes_per_pixel * width);
407     memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * width);
408     i += bytes_per_row;
409     }
410     }
411     }
412     #endif
413    
414     #endif /* ENABLE_VOSF */
415    
416     #endif /* VIDEO_VOSF_H */