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

# Content
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 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 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 #define FB_DEPTH 0
94 #define FB_FUNC_NAME do_fbcopy_raw
95 #include "video_blit.h"
96 #endif
97
98
99 // RGB 555
100
101 #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 #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 #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 // opposite byte order
134
135 #define FB_BLIT_1(dst, src) \
136 (dst = ((((src) >> 7) & 0xff) | (((src) << 9) & 0xc000) | (((src) << 8) & 0x1f00)))
137
138 #define FB_BLIT_2(dst, src) \
139 (dst = ((((src) >> 7) & 0x00ff00ff) | (((src) << 9) & 0xc000c000) | (((src) << 8) & 0x1f001f00)))
140
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 #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 #define FB_FUNC_NAME do_fbcopy_16_nbo
157 #include "video_blit.h"
158
159 // 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
173 // RGB 888
174
175 #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 #define FB_BLIT_1(dst, src) \
182 (dst = (src))
183
184 #define FB_BLIT_2(dst, src) \
185 (dst = (((src) >> 24) & 0xff) | (((src) >> 8) & 0xff00) | (((src) & 0xff00) << 8) | (((src) & 0xff) << 24))
186
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 // NBO : native byte order (X server vs. client)
210 // OBO : opposite byte order (X server vs. client)
211 static fbcopy_func fbcopy_funcs[ID_DEPTH_COUNT][2][2] = {
212 #ifdef WORDS_BIGENDIAN
213 /* 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 /* 15 bpp */ { WD(fbcopy_15_obo) , WD(fbcopy_raw) }, // OK (OBO)
217 /* 16 bpp */ { WD(fbcopy_16_obo) , WD(fbcopy_16_nbo) }, // OK (OBO)
218 /* 24 bpp */ { WD(fbcopy_24_obo) , WD(fbcopy_raw) } // OK (OBO)
219 #else
220 /* 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 /* 24 bpp */ { WD(fbcopy_raw) , WD(fbcopy_24_nbo) } // OK (NBO)
226 #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 const uintptr INVALID_PC = (uintptr)-1;
244
245 static inline void do_handle_screen_fault(uintptr addr, uintptr pc = INVALID_PC)
246 {
247 /* 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 }
260
261 /* 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 }
269
270 #if defined(HAVE_SIGINFO_T)
271
272 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 do_handle_screen_fault((uintptr)sip->si_addr);
276 }
277
278 #elif defined(HAVE_SIGCONTEXT_SUBTERFUGE)
279
280 # 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 do_handle_screen_fault((uintptr)scs.cr2, (uintptr)scs.eip);
285 }
286
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 # 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 vosf_sa.sa_flags = SA_SIGINFO;
330 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 #if !EMULATED_68K && defined(__NetBSD__)
339 sigaddset(&vosf_sa.sa_mask, SIGALRM);
340 vosf_sa.sa_flags = SA_ONSTACK;
341 #else
342 vosf_sa.sa_flags = 0;
343 #endif
344 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 const int first_page = find_next_page_set(page);
358 if (first_page >= mainBuffer.pageCount)
359 break;
360
361 page = find_next_page_clear(first_page);
362 PFLAG_CLEAR_RANGE(first_page, page);
363
364 // 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 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 }
393 }
394
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 x2 = (i << 3) + 7;
402 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
431 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 }
441 }
442 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 }
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 const int first_page = find_next_page_set(page);
473 if (first_page >= mainBuffer.pageCount)
474 break;
475
476 page = find_next_page_clear(first_page);
477 PFLAG_CLEAR_RANGE(first_page, page);
478
479 // 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 */